CORS errors on Azure Translator API (Cognitive Services) when using Aurelia's Fetch Client

大兔子大兔子 提交于 2019-12-13 16:23:03

问题


I try to use a very basic API call from Windows Azure to translate some texts. They gives a quickstart example code.

I try this code and it works pretty well. The text Hello world is translated into deutch and italian.

I removed my personal subscription key.

Here is the sample:

const request = require('request');
const uuidv4 = require('uuid/v4');

const subscriptionKey = '........';

let options = {
    method: 'POST',
    baseUrl: 'https://api.cognitive.microsofttranslator.com/',
    url: 'translate',
    qs: {
      'api-version': '3.0',
      'to': ['de', 'it']
    },
    headers: {
      'Ocp-Apim-Subscription-Key': subscriptionKey,
      'Content-type': 'application/json',
      'X-ClientTraceId': uuidv4().toString()
    },
    body: [{
          'text': 'Hello World!'
    }],
    json: true,
};

request(options, function(err, res, body){
    console.log(JSON.stringify(body, null, 4));
});

It looks like this code is a server side library for node. Now I need to integrate this code into my [aurelia][2] application. So I think of using the aurelia-fetch-client to replace the request method. I use the Aurelia CLI.

Here is what I did:

Added in package.json:

"dependencies": {
    ....
    "@types/uuidv4": "^2.0.0",
    ...
    "uuidv4": "^4.0.0",
}

Added in aurelia.json:

"dependencies": [
      ...
      "uuidv4"
]

Run npm install inside my console.

Created a test page:

import { HttpClient, json } from 'aurelia-fetch-client';
import { autoinject } from 'aurelia-framework';
import * as uuidv4 from 'uuidv4';
import secret from '../secret';

@autoinject
export class Translator {
    constructor(httpClient: HttpClient) {
        this.httpClient = httpClient;
    }
    private httpClient: HttpClient;
    private translate(from, to, html) {

        debugger;

        var init: RequestInit =
        {
            method: 'POST',
            //mode: 'no-cors',
            headers: {
                'Ocp-Apim-Subscription-Key': secret.translatorKey,
                'Content-type': 'application/json',
              //'Content-Type': 'application/x-www-form-urlencoded',
                'X-ClientTraceId': uuidv4().toString()
            },
            credentials: 'same-origin',
            body: $.param({
                'api-version': '3.0',
                'from': 'en',
                'to': 'fr',
                'text': '<b>Hello World!</b>' })
          //body: json({ 'text': '<b>Hello World!</b>' })
        };

   this.httpClient.fetch(`https://api.cognitive.microsofttranslator.com/`, init)
    .then((result) => {   
        debugger;
    })
    .catch((error) => {
        debugger;
    });

}

The trick is to be able to get the options passed to the request of the sample code and adjust it to the aurelia-fetch-client. I did not succeed.

Unfortunately I always get the error below:

Access to fetch at 'https://api.cognitive.microsofttranslator.com/' from origin 'http://localhost:9000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.

Any suggestions ?


回答1:


TL;DR - Just like you, I'm having a hard time getting the instructions from the documentation working in the browser. However, appending the Subscription-Key as querystring parameter does seem to work.

Example, and please read the comments:

import { HttpClient } from 'aurelia-fetch-client';
import { autoinject } from 'aurelia-framework';

@autoinject
export class App {

  constructor(private http: HttpClient) {
  }

  private async attached(): Promise<void> {

    // Important: use either key1 or key2, not the guid from your subscription
    const subscriptionKey = 'YOUR-KEY-HERE';

    // Important: the endpoint is different per GEO-REGION
    const baseUrl = 'https://api-eur.cognitive.microsofttranslator.com';

    const body = [{
      'text': 'Hello World!'
    }];

    // Note: I couldn't get 'Ocp-Apim-Subscription-Key' working in the browser (only through Postman, curl)
    // Also, trading in the subscriptionKey for a Bearer token did not work for me (in the browser)
    // Therefor, we append it to the url later on.
    // Also notice, X-ClientTraceId' is NOT neccessary and the docs don't explain why it's needed
    const headers = new Headers();
    headers.append('Content-Type', 'application/json');

    const response = await this.http.fetch(`${baseUrl}/translate?api-version=3.0&to=nl&Subscription-Key=${subscriptionKey}`, {
      method: 'POST',
      headers: headers,
      body: JSON.stringify(body)
    });

    if (response.ok) console.log(await response.json());
  }
}

Note that for this example, you don't need request and uuid libraries. You just need:

$ npm install --save aurelia-fetch-client whatwg-fetch

I also noticed you're using TypeScript, so changed the example to use that by using @autoinject.

The longer story

If you're getting a lot of 401's - there is an older MSDN blogpost which is still definitely worth a read. Some highlights:

  • There are different API endpoints depending on the geolocation of your Azure service.
  • There is a difference in endpoints between the individual services (Translator, Vision etc.) which are geo-region based - and the generic, broader Cognitive Services (a.k.a. the Cognitive multi-service subscription).
  • If you're using individual services, API keys are different per service.
  • There are 3 different ways of authenticating; however, I can only get one of them to work in the browser.

This is also more or less written in the official docs.

That being said, the example in the docs aren't really any good. At least, in my opinion. First, you want to make sure you know exactly what you're supposed to do. Here is a curl example:

curl -X POST \
  'https://api-eur.cognitive.microsofttranslator.com/translate?api-version=3.0&to=nl' \
  -H 'Content-Type: application/json' \
  -H 'Ocp-Apim-Subscription-Key: <YOUR-KEY-HERE>' \
  -d '[{
    '\''text'\'': '\''Hello World!'\''
}]'

While this sounds easy, I cannot get this to work properly in the browser where I keep getting what appears to be CORS issues with 401's. The cause seems to be it doesn't swallow the 'Ocp-Apim-Subscription-Key'. I've also tried trading in the subscriptionKey for an Authorization Bearer token (example) which also didn't work in the browser. These examples do work in curl, or in Postman though.

Finally, just falling back to using the SubscriptionKey as querystring helped. At least, for me.

Hope this helps!



来源:https://stackoverflow.com/questions/57267326/cors-errors-on-azure-translator-api-cognitive-services-when-using-aurelias-fe

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!