Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
518 views
in Technique[技术] by (71.8m points)

javascript - 尝试从REST API获取数据时,请求的资源上没有“ Access-Control-Allow-Origin”标头(No 'Access-Control-Allow-Origin' header is present on the requested resource—when trying to get data from a REST API)

I'm trying to fetch some data from the REST API of HP Alm.

(我正在尝试从HP Alm的REST API中获取一些数据。)

It works pretty well with a small curl script - I get my data.

(它与一个小的curl脚本一起使用时效果很好-我得到了数据。)

Now doing that with JavaScript, fetch and ES6 (more or less) seems to be a bigger issue.

(现在使用JavaScript进行操作,获取和ES6(或多或少)似乎是一个更大的问题。)

I keep getting this error message:

(我不断收到此错误消息:)

Fetch API cannot load .

(提取API无法加载。)

Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

(对预检请求的响应未通过访问控制检查:请求的资源上不存在“ Access-Control-Allow-Origin”标头。)

Origin ' http://127.0.0.1:3000 ' is therefore not allowed access.

(因此,不允许访问源' http://127.0.0.1:3000 '。)

The response had HTTP status code 501. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

(响应的HTTP状态码为501。如果不透明响应满足您的需求,请将请求的模式设置为“ no-cors”,以在禁用CORS的情况下获取资源。)

I understand that this is because I am trying to fetch that data from within my localhost and the solution should be using CORS.

(我了解这是因为我正在尝试从本地主机中获取数据,并且解决方案应使用CORS。)

Now I thought I actually did that, but somehow it either ignores what I write in the header or the problem is something else?

(现在我以为我确实这样做了,但是以某种方式它要么忽略了我在标题中写的内容,要么是其他问题?)

So, is there an implementation issue?

(那么,是否存在实施问题?)

Am I doing it wrong?

(我做错了吗?)

I can't check the server logs unfortunately.

(我无法检查服务器日志。)

I'm really a bit stuck here.

(我真的有点卡在这里。)

function performSignIn() {

  let headers = new Headers();

  headers.append('Content-Type', 'application/json');
  headers.append('Accept', 'application/json');

  headers.append('Access-Control-Allow-Origin', 'http://localhost:3000');
  headers.append('Access-Control-Allow-Credentials', 'true');

  headers.append('GET', 'POST', 'OPTIONS');

  headers.append('Authorization', 'Basic ' + base64.encode(username + ":" + password));

  fetch(sign_in, {
      //mode: 'no-cors',
      credentials: 'include',
      method: 'POST',
      headers: headers
    })
    .then(response => response.json())
    .then(json => console.log(json))
    .catch(error => console.log('Authorization failed : ' + error.message));
}

I am using Chrome.

(我正在使用Chrome。)

I also tried using that Chrome CORS Plugin, but then I am getting another error message:

(我也尝试使用该Chrome CORS插件,但是随后出现另一条错误消息:)

The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.

(当请求的凭据模式为“ include”时,响应中“ Access-Control-Allow-Origin”标头的值不得为通配符“ *”。)

Origin ' http://127.0.0.1:3000 ' is therefore not allowed access.

(因此,不允许访问源' http://127.0.0.1:3000 '。)

The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.

(XMLHttpRequest发起的请求的凭据模式由withCredentials属性控制。)

  ask by daniel.lozynski translate from so

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

This answer covers a lot of ground, so it's divided into three parts:

(该答案涉及很多领域,因此分为三个部分:)

  • How to use a CORS proxy to get around “No Access-Control-Allow-Origin header” problems

    (如何使用CORS代理来解决“无访问控制-允许-来源标头”问题)

  • How to avoid the CORS preflight

    (如何避免CORS飞行前)

  • How to fix “Access-Control-Allow-Origin header must not be the wildcard” problems

    (如何解决“ Access-Control-Allow-Origin标头一定不能为通配符”的问题)


How to use a CORS proxy to get around “No Access-Control-Allow-Origin header” problems

(如何使用CORS代理来解决“无访问控制-允许-来源标头”问题)

If you don't control the server your frontend JavaScript code is sending a request to, and the problem with the response from that server is just the lack of the necessary Access-Control-Allow-Origin header, you can still get things to work—by making the request through a CORS proxy.

(如果您不控制服务器,您的前端JavaScript代码正在向其发送请求,并且该服务器的响应问题仅在于缺少必要的Access-Control-Allow-Origin标头,那么您仍然可以使事情正常进行-通过CORS代理发出请求。)

To show how that works, first here's some code that doesn't use a CORS proxy:

(为了展示它是如何工作的,首先这里是一些不使用CORS代理的代码:)

 const url = "https://example.com"; // site that doesn't send Access-Control-* fetch(url) .then(response => response.text()) .then(contents => console.log(contents)) .catch(() => console.log("Can't access " + url + " response. Blocked by browser?")) 

The reason the catch block gets hit there is, the browser prevents that code from accessing the response which comes back from https://example.com .

(导致catch块被击中的原因是,浏览器阻止该代码访问来自https://example.com的响应。)

And the reason the browser does that is, the response lacks the Access-Control-Allow-Origin response header.

(而浏览器这样做的原因是,该响应缺少Access-Control-Allow-Origin响应标头。)

Now, here's exactly the same example but just with a CORS proxy added in:

(现在,这是完全相同的示例,只是在其中添加了CORS代理:)

 const proxyurl = "https://cors-anywhere.herokuapp.com/"; const url = "https://example.com"; // site that doesn't send Access-Control-* fetch(proxyurl + url) // https://cors-anywhere.herokuapp.com/https://example.com .then(response => response.text()) .then(contents => console.log(contents)) .catch(() => console.log("Can't access " + url + " response. Blocked by browser?")) 

Note: If https://cors-anywhere.herokuapp.com is down or unavailable when you try it, then see below for how to deploy your own CORS Anywhere server at Heroku in just 2-3 minutes.

(注意:如果在尝试https://cors-anywhere.herokuapp.com时关闭或不可用,请参见下文,了解如何在2-3分钟内在Heroku上部署自己的CORS Anywhere服务器。)

The second code snippet above can access the response successfully because taking the request URL and changing it to https://cors-anywhere.herokuapp.com/https://example.com —by just prefixing it with the proxy URL—causes the request to get made through that proxy, which then:

(上面的第二个代码段可以成功访问响应,因为采用请求URL并将其更改为https://cors-anywhere.herokuapp.com/https://example.com(仅在其前面加上代理URL)会导致请求通过该代理取得,然后:)

  1. Forwards the request to https://example.com .

    (将请求转发到https://example.com 。)

  2. Receives the response from https://example.com .

    (从https://example.com接收响应。)

  3. Adds the Access-Control-Allow-Origin header to the response.

    (将Access-Control-Allow-Origin标头添加到响应中。)

  4. Passes that response, with that added header, back to the requesting frontend code.

    (将带有添加的标头的响应传递回请求的前端代码。)

The browser then allows the frontend code to access the response, because that response with the Access-Control-Allow-Origin response header is what the browser sees.

(然后,浏览器允许前端代码访问响应,因为带有Access-Control-Allow-Origin响应标头的响应就是浏览器看到的内容。)

You can easily run your own proxy using code from https://github.com/Rob--W/cors-anywhere/ .

(您可以使用https://github.com/Rob--W/cors-anywhere/中的代码轻松运行自己的代理。)
You can also easily deploy your own proxy to Heroku in literally just 2-3 minutes, with 5 commands:

(您还可以使用5条命令在2-3分钟内轻松地将您自己的代理部署到Heroku中:)

git clone https://github.com/Rob--W/cors-anywhere.git
cd cors-anywhere/
npm install
heroku create
git push heroku master

After running those commands, you'll end up with your own CORS Anywhere server running at, eg, https://cryptic-headland-94862.herokuapp.com/ .

(运行完这些命令后,您将最终在以下位置运行自己的CORS Anywhere服务器,例如https://cryptic-headland-94862.herokuapp.com/ 。)

So then rather than prefixing your request URL with https://cors-anywhere.herokuapp.com , prefix it instead with the URL for your own instance;

(因此,不要在请求URL前面加上https://cors-anywhere.herokuapp.com ,而是在您自己的实例的URL前面加上前缀;)

eg, https://cryptic-headland-94862.herokuapp.com/https://example.com .

(例如https://cryptic-headland-94862.herokuapp.com/https://example.com 。)

So if when you go to try to use https://cors-anywhere.herokuapp.com, you find it's down (which it sometimes will be), then consider getting a Heroku account (if you don't already) and take 2 or 3 minutes to do the steps above to deploy your own CORS Anywhere server on Heroku.

(因此,如果您尝试使用https://cors-anywhere.herokuapp.com时发现它已关闭 (有时会出现故障 ),那么可以考虑获取一个Heroku帐户(如果您尚未使用)并拿2或花费3分钟完成上述步骤,以在Heroku上部署您自己的CORS Anywhere服务器。)

Regardless, whether you run your own or use https://cors-anywhere.herokuapp.com or other open proxy, this solution will work even if the request is one that triggers browsers to do a CORS preflight OPTIONS request—because in that case, the proxy also sends back the Access-Control-Allow-Headers and Access-Control-Allow-Methods headers needed to make the preflight successful.

(无论您是运行自己的网站还是使用https://cors-anywhere.herokuapp.com或其他开放式代理,即使该请求是触发浏览器执行CORS预检OPTIONS请求的请求,该解决方案都将起作用-因为在这种情况下,代理还会发回使预检成功所需的Access-Control-Allow-HeadersAccess-Control-Allow-Methods头。)


How to avoid the CORS preflight

(如何避免CORS飞行前)

The code in the question triggers a CORS preflight—since it sends an Authorization header.

(问题中的代码会触发CORS预检-因为它发送了Authorization标头。)

https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests

(https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS#Preflighted_requests)

Even without that, the Content-Type: application/json header would also trigger the preflight.

(即使没有这些Content-Type: application/jsonContent-Type: application/json标头也将触发预检。)

What “preflight” means: before the browser tries the POST in the code in the question, it'll first send an OPTIONS request to the server — to determine if the server is opting-in to receiving a cross-origin POST that includes the Authorization and Content-Type: application/json headers.

(“预检”的含义是:在浏览器尝试问题代码中的POST之前,它将首先向服务器发送OPTIONS请求-确定服务器是否选择接收包含以下内容的跨域POSTAuthorizationContent-Type: application/json标头。)

It works pretty well with a small curl script - I get my data.

(它与一个小的curl脚本一起使用时效果很好-我得到了数据。)

To properly test with curl , you need to emulate the preflight OPTIONS request the browser sends:

(为了正确地使用curl测试,您需要模拟浏览器发送的预检OPTIONS请求:)

curl -i -X OPTIONS -H "Origin: http://127.0.0.1:3000" 
    -H 'Access-Control-Request-Method: POST' 
    -H 'Access-Control-Request-Headers: Content-Type, Authorization' 
    "https://the.sign_in.url"

…with https://the.sign_in.url replaced by whatever your actual sign_in URL is.

(…将https://the.sign_in.url替换为您实际的sign_in URL。)

The response the browser needs to see from that OPTIONS request must include headers like this:

(浏览器需要从该OPTIONS请求中看到的响应必须包括以下标头:)

Access-Control-Allow-Origin:  http://127.0.0.1:3000
Access-Control-Allow-Methods: POST
Access-Control-Allow-Headers: Content-Type, Authorization

If the OPTIONS response doesn't include those headers, then the browser will stop right there and never even attempt to send the POST request.

(如果OPTIONS响应不包含这些标头,则浏览器将在那里停止,甚至从不尝试发送POST请求。)

Also, the HTTP status code for the response must be a 2xx—typically 200 or 204. If it's any other status code, the browser will stop right there.

(另外,响应的HTTP状态代码必须为2xx,通常为200或204。如果是其他任何


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...