typescript - 使用 Aurelia 的 Fetch Client 时 Azure Translator API(认知服务)上出现 CORS 错误

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

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

我尝试了这段代码,效果很好。文本 Hello world 被翻译成德语和意大利语。

我删除了我的个人订阅 key 。

这是示例:

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/ 获取数据'来自原点'http://localhost:9000 ' 已被 CORS 策略阻止:对预检请求的响应未通过访问控制检查:预检请求不允许重定向。

有什么建议吗?

最佳答案

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

示例,请阅读评论:

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 key 都不同。
  • 有 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”。我还尝试过用 subscriptionKey 换取授权承载 token ( example ),但这在浏览器中也不起作用。这些示例在curl 或Postman 中确实有效。

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

希望这有帮助!

关于typescript - 使用 Aurelia 的 Fetch Client 时 Azure Translator API(认知服务)上出现 CORS 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57267326/

相关文章:

javascript - 当我在 javascript 中手动创建列表时,无法使用 querySelectorAll(); 获取值;

typescript - 如何实现具有多个函数调用签名的 typescript 接口(interface)

xmlhttprequest - 请求头字段X-Requested

javascript - 如何使用 Access-Control-Allow-Origin : https://www. example.com?

javascript - firebase js 版本 > 3.6.3 破坏了与 aurelia-cli 的捆绑

javascript - PHP session 在 Aurelia 中不起作用

angular - Http 请求头映射为空

angular - 如何使用事件发射器触发子组件和父组件中的函数?

html - 服务器发送的事件是否适用于 CORS?

javascript - Aurelia-repeat.for json