node.js CORS 飞行前返回 Access-Control-Allow-Origin:*,浏览器仍然无法请求

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18003605/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 15:10:33  来源:igfitidea点击:

CORS pre-flight comes back with Access-Control-Allow-Origin:*, browser still fails request

javascriptnode.jsexpresscorsjqxhr

提问by tnunamak

Triggering an AJAX GETto http://qualifiedlocalhost:8888/resource.jsonkicks off the expected CORS pre-flight, which looks like it comes back correctly:

触发 AJAXGEThttp://qualifiedlocalhost:8888/resource.json启动预期的 CORS 预检,看起来它正确返回:

Pre-flight OPTIONSrequest

飞行前OPTIONS请求

Request URL:http://qualifiedlocalhost:8888/resource.json
Request Method:OPTIONS
Status Code:200 OK

Request Headers

请求头

Accept:*/*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Access-Control-Request-Headers:accept, origin, x-requested-with
Access-Control-Request-Method:GET
Cache-Control:no-cache
Connection:keep-alive
Host:qualifiedlocalhost:8888
Origin:http://localhost:9000
Pragma:no-cache
Referer:http://localhost:9000/
User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.71 Safari/537.36

Response Headers

响应头

Access-Control-Allow-Headers:Content-Type, X-Requested-With
Access-Control-Allow-Methods:GET,PUT,POST,DELETE
Access-Control-Allow-Origin:*
Connection:keep-alive
Content-Length:2
Content-Type:text/plain
Date:Thu, 01 Aug 2013 19:57:43 GMT
Set-Cookie:connect.sid=s%3AEpPytDm3Dk3H9V4J9y6_y-Nq.Rs572s475TpGhCP%2FK%2B2maKV6zYD%2FUg425zPDKHwoQ6s; Path=/; HttpOnly
X-Powered-By:Express

Looking good?

看起来不错?

So it should work, right?

所以它应该有效,对吧?

But the subsequent request still fails with the error XMLHttpRequest cannot load http://qualifiedlocalhost:8888/resource.json. Origin http://localhost:9000 is not allowed by Access-Control-Allow-Origin.

但是后续请求仍然失败并报错 XMLHttpRequest cannot load http://qualifiedlocalhost:8888/resource.json. Origin http://localhost:9000 is not allowed by Access-Control-Allow-Origin.

True request

真实请求

Request URL:http://qualifiedlocalhost:8888/resource.json

Request Headers

请求头

Accept:application/json, text/plain, */*
Cache-Control:no-cache
Origin:http://localhost:9000
Pragma:no-cache
Referer:http://localhost:9000/
User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.71 Safari/537.36
X-Requested-With:XMLHttpRequest

Help!

帮助!

Maybe it's staring right in front of me. But, any ideas? Just in case it's relevant... I'm using an AngularJS $resourceand talking to a CompoundJS server.

也许它就在我眼前。但是,有什么想法吗?以防万一它是相关的……我正在使用 AngularJS$resource并与 CompoundJS 服务器交谈。

回答by KARTHIKEYAN.A

change your Access-Control-Allow-Methods: 'GET, POST' to 'GET, POST, PUT, DELETE'

将您的 Access-Control-Allow-Methods: 'GET, POST' 更改为 'GET, POST, PUT, DELETE'

before:

前:

   app.use(function(req, res, next) {
        res.setHeader('Access-Control-Allow-Origin', '*');
        res.setHeader('Access-Control-Allow-Methods', 'GET, POST');
        res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type, Authorization');
        next();
    });

After:

后:

app.use(function(req, res, next) {
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT ,DELETE');
    res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type, Authorization');
    next();
});

回答by BlueRaja - Danny Pflughoeft

I recently had the same issue. The problem is that the Access-Control-Allow-Originheader (and, if you use it, the Access-Control-Allow-Credentialsheader) must be sent in boththe preflight response and the actual response.

最近遇到了同样的问题。问题是,在Access-Control-Allow-Origin头(如果你使用它,将Access-Control-Allow-Credentials头)必须在发送两个预检响应和实际响应。

Your example has it only in the preflight response.

您的示例仅在预检响应中包含它。

回答by Jeff Collier

Is your web server/get function ALSO including the HTTP header: Access-Control-Allow-Origin? I eventually found success with that addition, using AngularJS 1.0.7 and a remote Java servlet. Here is my Java code snippet--no changes were required in AngularJS client:

您的 Web 服务器/获取功能是否还包括 HTTP 标头:Access-Control-Allow-Origin?我最终通过使用 AngularJS 1.0.7 和远程 Java servlet 获得了成功。这是我的 Java 代码片段——在 AngularJS 客户端中不需要任何更改:

Servlet:

小服务程序:

@Override
protected void doOptions(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // Send Response
    super.doOptions(request,  response);
    response.setHeader("Access-Control-Allow-Origin", "*");
    response.setHeader("Access-Control-Allow-Headers", "Content-Type, X-Requested-With");
}

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    /* ... */
    response.setHeader("Access-Control-Allow-Origin", "*");
}

A more elegant alternative is a servlet filter.

一个更优雅的替代方案是 servlet 过滤器。

回答by Shyam Habarakada

We have been noticing the same issue, where the server is sending the correct CORS headers, but the browser fails because it thinks the CORS requirements are not being met. More interestingly, in our case, it only happens on some AJAX calls in the same browser session, but not all.

我们已经注意到同样的问题,服务器发送正确的 CORS 标头,但浏览器失败,因为它认为没有满足 CORS 要求。更有趣的是,在我们的例子中,它只发生在同一个浏览器会话中的一些 AJAX 调用上,而不是全部。

Working theory...

工作原理...

Clearing the browser cache solves the problem in our case -- My current working theory is that this has something to do with cookies being set by the cross origin server. I noticed in your scenario, there is a cookie being set as part of the response to the pre-flight OPTIONS request. Have you tried making that server not set any cookies for requests coming from a different origin?

清除浏览器缓存解决了我们的问题——我目前的工作理论是,这与跨源服务器设置的 cookie 有关。我注意到在你的场景中,有一个 cookie 被设置为对飞行前 OPTIONS 请求的响应的一部分。您是否尝试过让该服务器不对来自不同来源的请求设置任何 cookie?

However, we've noticed that in some cases, the problem re-appeared after resetting the browser. Also, running the browser in in-private mode causes the problem to go away, pointing to some problem to do with what's in the browser cache.

但是,我们注意到在某些情况下,重置浏览器后问题再次出现。此外,以私密模式运行浏览器会导致问题消失,这表明浏览器缓存中存在一些问题。

For reference, here is my scenario (I almost posted this as a new question in SO, but putting it here instead):

作为参考,这是我的场景(我几乎将其发布为 SO 中的一个新问题,但将其放在这里):

We ran into a bug where someCORS GET requests made via jQuery.ajax were failing. In a given browser session, we see the pre-flight OPTIONS request go through, followed by the actual request. In the same session, some requests go through and others fail.

我们遇到了一个错误,其中一些通过 jQuery.ajax 发出的 CORS GET 请求失败。在给定的浏览器会话中,我们看到飞行前 OPTIONS 请求通过,然后是实际请求。在同一个会话中,一些请求通过,而另一些请求失败。

The sequence of requests and responses in the browser network console look like below:

浏览器网络控制台中的请求和响应序列如下所示:

First the OPTIONS pre-flight request

首先是 OPTIONS 飞行前请求

OPTIONS /api/v1/users/337/statuses
HTTP/1.1 Host: api.obfuscatedserver.com 
Connection: keep-alive 
Access-Control-Request-Method: GET 
Origin: http://10.10.8.84:3003 
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36
Access-Control-Request-Headers: accept, origin, x-csrf-token, auth 
Accept: */* Referer: http://10.10.8.84:3003/ 
Accept-Encoding: gzip,deflate,sdch Accept-Language: en-US,en;q=0.8

Which gets a response like,

得到这样的回应,

HTTP/1.1 200 OK 
Date: Tue, 06 Aug 2013 19:18:22 GMT 
Server: Apache/2.2.22 (Ubuntu) 
Access-Control-Allow-Origin: http://10.10.8.84:3003 
Access-Control-Allow-Methods: GET, POST, OPTIONS, PUT 
Access-Control-Max-Age: 1728000 
Access-Control-Allow-Credentials: true 
Access-Control-Allow-Headers: accept, origin, x-csrf-token, auth 
X-UA-Compatible: IE=Edge,chrome=1 
Cache-Control: no-cache 
X-Request-Id: 4429c4ea9ce12b6dcf364ac7f159c13c 
X-Runtime: 0.001344 
X-Rack-Cache: invalidate, pass 
X-Powered-By: Phusion 
Passenger 4.0.2 
Status: 200 OK 
Vary: Accept-Encoding
Content-Encoding: gzip

Then the actual GET request,

然后是实际的 GET 请求,

GET https://api.obfuscatedserver.com/api/v1/users/337
HTTP/1.1 
Accept: application/json, text/javascript, */*; q=0.01 
Referer: http://10.10.8.84:3003/ 
Origin: http://10.10.8.84:3003 
X-CSRF-Token: xxxxxxx 
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36 
auth: xxxxxxxxx

Which gets an error in the browser console like,

在浏览器控制台中出现错误,例如,

XMLHttpRequest
  cannot load https://api.obfuscatedserver.com/api/v1/users/337.
  Origin http://10.10.8.84:3003 is not allowed by Access-Control-Allow-Origin.

Additional Debugging

附加调试

I can replay the same sequence via curl, and I see valid responses coming from the server. i.e. they have the expected CORS headers that should let the requests go through.

我可以通过 curl 重放相同的序列,并且我看到来自服务器的有效响应。即他们有应该让请求通过的预期 CORS 标头。

Running the same scenario in an in-private / incognito browser window did not reproduce the problem. This lead me to try clearing the cache, and that made the problem go away too. But after a while, it came back.

在私密/隐身浏览器窗口中运行相同的场景没有重现该问题。这导致我尝试清除缓存,这也使问题消失了。但过了一会儿,它又回来了。

The issue was reproducing on iPhone safari as well as on Chrome on OSX desktop.

该问题在 iPhone Safari 以及 OSX 桌面版 Chrome 上重现。

What I really need help with

我真正需要帮助的是什么

I'm suspecting there are some cookies set in the cross-origin domain that are getting involved here and potentially exposing a bug in the browser. Are there tools or breakpoints I can set in the browser (native stack?) to try and debug this further? A breakpoint in the code that evaluates the CORS policy would be ideal.

我怀疑在跨域域中设置了一些 cookie,这些 cookie 涉及到这里并可能暴露浏览器中的错误。我可以在浏览器(本机堆栈?)中设置工具或断点来尝试进一步调试吗?评估 CORS 策略的代码中的断点将是理想的。

回答by Larry Kang

Looks like your response to 'options' is working fine. The problem seems to be in the 'get' response.

看起来您对“选项”的回应工作正常。问题似乎出在“get”响应中。

You'll want to have your 'get' response return the same CORS headers as the 'options' response.

您希望“get”响应返回与“options”响应相同的 CORS 标头。

In particular, 'get' response should include

特别是,“get”响应应包括

Access-Control-Allow-Headers:Content-Type, X-Requested-With
Access-Control-Allow-Methods:GET,PUT,POST,DELETE
Access-Control-Allow-Origin:*

回答by KARTHIKEYAN.A

use cors module to avoid the problem

使用 cors 模块来避免这个问题

var cors = require('cors')

var app = express()
app.use(cors())