由于 CORS,HTTP 身份验证请求在浏览器中失败,在 Node 中正常
HTTP Auth request fails in browser due to CORS, ok in Node
我一直在尝试诊断一个问题,即使用 HTTP Basic Auth 的 GET 请求在 Node 中成功,但在浏览器中失败。该问题直接表现为 CORS 故障(401 页面上没有 Access-Control-Allow-Origin)。
request.js:119 OPTIONS http://HOST?PARAMS 401 (Unauthorized)
ClientRequest._onFinish @ request.js:119
(anonymous) @ request.js:61
...
17:53:59.170 localhost/:1 Failed to load http://HOST?PARAMS: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:9966' is therefore not allowed access. The response had HTTP status code 401. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
请求如下所示:
const request = require("request-promise");
const options = {"url":"http://...?","auth":{"user":"...","pass":"..."},"json":true,"qs":{...},"headers":{},"resolveWithFullResponse":true}
request.get(options).then(...);
此请求在 Chrome 中的显示方式:
这里让我感到惊讶的是:
- 方法是OPTIONS,不是GET。 (我没有明确要求。)
- 我的身份验证凭据未包含在 headers 中(即使我没有设置
sendImmediately: false
- "Provisional headers are shown" 警告。
我想知道的:
- 这是预期的行为吗?
- 如果不是,出了什么问题?
- 如果是,出现了什么问题? :)
运行 命令行上的等效请求似乎工作正常:
curl -I 'http://MYUSERNAME:MYPASSWORD@SAMEURL?SAME=PARAMETERS' -H 'Origin: http://localhost:4466' -X OPTIONS
HTTP/1.1 200 OK
Date: Wed, 20 Jun 2018 07:29:28 GMT
Server: Apache-Coyote/1.1
Access-Control-Allow-Origin: http://localhost:4466
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: Access-Control-Allow-Origin,Access-Control-Allow-Credentials
Vary: Origin
X-Frame-Options: SAMEORIGIN
Allow: GET,HEAD,POST,OPTIONS
Content-Length: 0
但是我注意到,如果 URL 中没有提供凭据,响应中就没有 CORS headers:
HTTP/1.1 401 Unauthorized
Date: Wed, 20 Jun 2018 07:45:26 GMT
Server: Apache/2.4.29 (Unix) OpenSSL/1.0.2l
WWW-Authenticate: Basic realm="Authentication Required"
Content-Length: 381
Content-Type: text/html; charset=iso-8859-1
这是正确的行为吗?
假设
我怀疑:
- 浏览器正在发送 OPTIONS "pre-flight" 请求,因为它必须这样做,因为该请求不是 "simple request"。 (不完全清楚这是请求库还是浏览器本身做的)
- 服务器正在响应 401,因为未提供凭据,但没有添加它应该添加的 CORS headers。
- 如果没有 CORS headers,浏览器会阻止请求库访问结果,因此无法完成身份验证。
我不确定的是:
- 服务器是否配置错误?
- Request 是否未能在 OPTIONS 预检请求中传递凭据?
服务器配置错误。它没有正确启用 CORS。要正确启用 CORS,它必须使用 200
或 204
状态代码响应未经身份验证的 OPTIONS
请求。
Request
并非“未能”在 OPTIONS
预检请求中传递凭据。 Request
甚至没有发出 OPTIONS
请求。相反,浏览器引擎是独立的。
并且在您自己的代码中为请求指定凭据标志不会导致将凭据添加到预检 OPTIONS
请求中。相反,凭据只会从您自己的代码中添加到 GET
请求中——也就是说,如果预检成功并且浏览器实际上会继续发出该 GET
请求。
这是因为 Fetch 规范中的 CORS 协议要求规定浏览器必须忽略预检 OPTIONS
请求中的所有凭据。
见https://fetch.spec.whatwg.org/#ref-for-credentials%E2%91%A5:
a CORS-preflight request never includes credentials
所以你遇到的行为是有意设计的。
有关更详细的相关解释,请参阅 的答案。
我一直在尝试诊断一个问题,即使用 HTTP Basic Auth 的 GET 请求在 Node 中成功,但在浏览器中失败。该问题直接表现为 CORS 故障(401 页面上没有 Access-Control-Allow-Origin)。
request.js:119 OPTIONS http://HOST?PARAMS 401 (Unauthorized)
ClientRequest._onFinish @ request.js:119
(anonymous) @ request.js:61
...
17:53:59.170 localhost/:1 Failed to load http://HOST?PARAMS: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:9966' is therefore not allowed access. The response had HTTP status code 401. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
请求如下所示:
const request = require("request-promise");
const options = {"url":"http://...?","auth":{"user":"...","pass":"..."},"json":true,"qs":{...},"headers":{},"resolveWithFullResponse":true}
request.get(options).then(...);
此请求在 Chrome 中的显示方式:
这里让我感到惊讶的是:
- 方法是OPTIONS,不是GET。 (我没有明确要求。)
- 我的身份验证凭据未包含在 headers 中(即使我没有设置
sendImmediately: false
- "Provisional headers are shown" 警告。
我想知道的:
- 这是预期的行为吗?
- 如果不是,出了什么问题?
- 如果是,出现了什么问题? :)
运行 命令行上的等效请求似乎工作正常:
curl -I 'http://MYUSERNAME:MYPASSWORD@SAMEURL?SAME=PARAMETERS' -H 'Origin: http://localhost:4466' -X OPTIONS
HTTP/1.1 200 OK
Date: Wed, 20 Jun 2018 07:29:28 GMT
Server: Apache-Coyote/1.1
Access-Control-Allow-Origin: http://localhost:4466
Access-Control-Allow-Credentials: true
Access-Control-Expose-Headers: Access-Control-Allow-Origin,Access-Control-Allow-Credentials
Vary: Origin
X-Frame-Options: SAMEORIGIN
Allow: GET,HEAD,POST,OPTIONS
Content-Length: 0
但是我注意到,如果 URL 中没有提供凭据,响应中就没有 CORS headers:
HTTP/1.1 401 Unauthorized
Date: Wed, 20 Jun 2018 07:45:26 GMT
Server: Apache/2.4.29 (Unix) OpenSSL/1.0.2l
WWW-Authenticate: Basic realm="Authentication Required"
Content-Length: 381
Content-Type: text/html; charset=iso-8859-1
这是正确的行为吗?
假设
我怀疑:
- 浏览器正在发送 OPTIONS "pre-flight" 请求,因为它必须这样做,因为该请求不是 "simple request"。 (不完全清楚这是请求库还是浏览器本身做的)
- 服务器正在响应 401,因为未提供凭据,但没有添加它应该添加的 CORS headers。
- 如果没有 CORS headers,浏览器会阻止请求库访问结果,因此无法完成身份验证。
我不确定的是:
- 服务器是否配置错误?
- Request 是否未能在 OPTIONS 预检请求中传递凭据?
服务器配置错误。它没有正确启用 CORS。要正确启用 CORS,它必须使用 200
或 204
状态代码响应未经身份验证的 OPTIONS
请求。
Request
并非“未能”在 OPTIONS
预检请求中传递凭据。 Request
甚至没有发出 OPTIONS
请求。相反,浏览器引擎是独立的。
并且在您自己的代码中为请求指定凭据标志不会导致将凭据添加到预检 OPTIONS
请求中。相反,凭据只会从您自己的代码中添加到 GET
请求中——也就是说,如果预检成功并且浏览器实际上会继续发出该 GET
请求。
这是因为 Fetch 规范中的 CORS 协议要求规定浏览器必须忽略预检 OPTIONS
请求中的所有凭据。
见https://fetch.spec.whatwg.org/#ref-for-credentials%E2%91%A5:
a CORS-preflight request never includes credentials
所以你遇到的行为是有意设计的。
有关更详细的相关解释,请参阅