使用 Aurelia's Fetch Client 时 Azure Translator API(认知服务)上的 CORS 错误



我尝试使用Windows Azure的非常基本的API调用来翻译一些文本。他们给出了快速启动示例代码。

我尝试此代码,并且效果很好。文本Hello world被翻译成Deutch和Italian。

我删除了我的个人订阅密钥。

这是示例:

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));
});

看起来此代码是node的服务器端库。现在,我需要将此代码集成到我的[Aurelia] [2]应用程序中。因此,我考虑使用aurelia-fetch-client替换request方法。我使用Aurelia Cli。

这是我所做的:

添加在package.json中:

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

在Aurelia.json中添加:

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

在我的控制台内运行npm install

创建了一个测试页面:

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;
    });
}

诀窍是能够将选项传递给示例代码的request并将其调整为aurelia-fetch-client。我没有成功。

不幸的是,我总是在下面遇到错误:

访问'https://api.cognitive.microsofttranslator.com/'来自Origin'http://localhost:9000'已被CORS策略阻止访问控制检查:不允许重定向以进行前飞行请求。

有什么建议?

tl; dr - 就像您一样,我很难从浏览器中工作的文档中获取说明。但是,将 Subscription-Key附加为querystring参数似乎确实有效。

示例,请阅读评论:

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());
  }
}

请注意,在此示例中,您不需要requestuuid库。您只需要:

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

我还注意到您正在使用Typescript,因此更改了使用@autoinject使用的示例。

较长的故事

如果您获得了很多401的功能 - 有一个较旧的MSDN博客文章,它绝对值得一读。一些亮点:

  • 根据您的Azure服务的地理位置,有不同的API端点。
  • 单个服务(翻译器,视觉等(之间的终点存在差异,这些服务是基于地理区域的 - 和通用,更广泛的认知服务(又称认知多服务订阅(。
  • 如果您使用的是单个服务,则每个服务的API密钥不同。
  • 有3种不同的认证方式;但是,我只能让其中一个在浏览器中工作。

这也或多或少地写在官方文档中。

话虽如此,文档中的示例并不好。最起码,我是这么想的。首先,您想确保确切知道应该做什么。这是一个卷曲示例:

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!'''
}]'

虽然听起来很容易,但我无法在浏览器中正常工作,在那里我继续获得401的CORS问题。原因似乎是因为它没有吞下" OCP-Apim-Subscription-key"。我还尝试在订阅中进行交易以获取授权携带者令牌(示例(,该授权人也不在浏览器中使用。这些示例确实在卷曲中或邮递员中起作用。

最后,只是回到使用订阅键,作为querystring有所帮助。至少对我而言。

希望这会有所帮助!

最新更新