问题
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