【问题标题】:CORS errors on Azure Translator API (Cognitive Services) when using Aurelia's Fetch Client使用 Aurelia 的 Fetch Client 时 Azure Translator API(认知服务)出现 CORS 错误
【发布时间】:2019-12-07 14:09:30
【问题描述】:

我尝试使用来自 Windows Azure 的一个非常基本的 API 调用来翻译一些文本。他们给了quickstart example code

我尝试了这段代码,它运行良好。文本Hello world 被翻译成德语和意大利语。

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

示例如下:

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。我没有成功。

不幸的是,我总是收到以下错误:

访问从源“http://localhost:9000”获取“https://api.cognitive.microsofttranslator.com/”已被 CORS 策略阻止:对预检请求的响应未通过访问控制检查:预检请求不允许重定向。

有什么建议吗?

【问题讨论】:

  • stackoverflow.com/a/42172732/441757 上查看答案。浏览器对https://api.cognitive.microsofttranslator.com/ 发出的COR preflight OPTIONS 请求的服务器响应显然是3xx 重定向。检查响应中的 Location 响应标头。您可以使用浏览器开发工具中的网络窗格来查看它。查看响应试图将您重定向到哪个 URL。
  • 还有类似thisthat的q&a与同一主题相关。这些适用于较旧的 Web 服务。 @sideshowbarker 可能对预检讨论的链接是正确的,但这不是可以在客户端解决的问题。不过,关于使用“订阅密钥”作为查询字符串的答案,我有多糟糕,可能会有所帮助。

标签: typescript cors aurelia azure-cognitive-services aurelia-fetch-client


【解决方案1】:

TL;DR - 就像您一样,我很难从浏览器中的文档中获取说明。但是,将 Subscription-Key 附加为查询字符串参数似乎确实有效。

示例,请阅读 cmets:

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 - 有一个 older MSDN blogpost 仍然绝对值得一读。一些亮点:

  • different API endpoints 取决于您的 Azure 服务的地理位置。
  • 基于地理区域的单个服务(翻译、视觉等)与通用的、更广泛的认知服务(也称为认知多服务订阅)之间的端点存在差异.
  • 如果您使用单个服务,则每个服务的 API 密钥都不同。
  • 有 3 种不同的身份验证方式;但是,我只能让其中一个在浏览器中工作。

这也或多或少写成in the official docs

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

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”。我还尝试在订阅密钥中交易授权持有者令牌 (example),该令牌在浏览器中也不起作用。这些示例在 curl 或 Postman 中确实有效。

最后,回退到使用 SubscriptionKey 作为查询字符串会有所帮助。至少,对我来说。

希望这会有所帮助!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-07-01
    • 2018-03-13
    • 2018-03-11
    • 1970-01-01
    • 1970-01-01
    • 2016-03-12
    • 2018-06-17
    • 2019-02-08
    相关资源
    最近更新 更多