目录
偷懒的配置
之前在本地调试跨域时,在返回时增加头,运行很顺利很顺利。
以下为部分配置:
location / {
index index.php ;
}
location ~ \.php(.*)$ {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Headers' '*';
add_header 'Access-Control-Allow-Methods' '*';
fastcgi_pass fastcgi_server;
fastcgi_index index.php;
fastcgi_split_path_info ^((?U).+\.php)(/?.+)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
include fastcgi_params;
}
遇到 withCredentials=true
- 客户端 withCredentials = true时,会向服务器发送 cookie
axios.defaults.withCredentials = true
"偷懒"的配置会报错
Response to preflight request doesn’t pass access control check: 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’. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
当credentials设置成 true 时,返回的 Access-Control-Allow-Origin 头就不能设置成 *
- 服务端配置中还需要增加:
add_header 'Access-Control-Allow-Credentials' 'true';
不然还会报错
Response to preflight request doesn’t pass access control check: The value of the ‘Access-Control-Allow-Credentials’ header in the response is ‘’ which must be ‘true’ when the request’s credentials mode is ‘include’. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
附带身份凭证的请求与通配符
对于附带身份凭证的请求,服务器不得设置 Access-Control-Allow-Origin 的值为“*”。
这是因为请求的首部中携带了 Cookie 信息,如果 Access-Control-Allow-Origin 的值为“*”,请求将会失败。而将 Access-Control-Allow-Origin 的值设置为 http://foo.example,则请求将成功执行。
另外,响应首部中也携带了 Set-Cookie 字段,尝试对 Cookie 进行修改。如果操作失败,将会抛出异常。
错误集中营
这是一个多种问题导致的错误集合,一个连一个,困扰了我一段时间,按道理是跨越的头已经配上了啊,不应该报错的吖。
简单描述这个请求:
- 请求时不带入口文件,使用默认初始页index.php,后续称为忽略网站入口
- 请求头为 Content-Type: application/json
忽略网站入口
因为设置了默认初始页,所以在前端写接口时忽略了网站入口,此时报错
Response to preflight request doesn’t pass access control check: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.
这里就是明明配置了却没有返回
常见的 Content-Type: application/json
在前端我们经常会直接提交一个json,在axios中会自动设置Content-Type: application/json。
此时预检通过,但后续请求会报错了!
Request header field content-type is not allowed by Access-Control-Allow-Headers in preflight response.
问题分析和解决方法
Content-Type
当 Content-Type: application/json 时,该请求不是一个简单请求,会触发CORS 预检,需要做以下修改
--- add_header 'Access-Control-Allow-Methods' '*'
+++ add_header 'Access-Control-Allow-Methods' 'Content-Type';
if ($request_method = 'OPTIONS') {
return 204;
}
忽略入口
在忽略了入口的情况下,CORS 预检的OPIONS请求会触发 location / 规则中的 nginx index指令,进行一次内部重定向,结果就是预检查失败,因为并没有如直觉看到的一样进入到 location ~ .php(.*)$ 规则中。所以会出现明明设置了头,但还是提示没有设置。按照这个思路,可以做一下修改:
改成不忽略入口
请求时增加文件后缀 ,即 http://127.0.0.4/?_x=home.index.set 改为 http://127.0.0.4/index.php?_x=home.index.set
依然忽略入口
此时情况也特别:
方法一
把add_header 放到外面,确保预检OPTIONS请求和后续的POST请求都可以收到正确的回复头。
add_header 'Access-Control-Allow-Origin' 'http://127.0.0.4:8080';
add_header 'Access-Control-Allow-Methods' '*';
add_header 'Access-Control-Allow-Headers' 'content-type';
add_header 'Access-Control-Allow-Credentials' 'true';
if ($request_method = 'OPTIONS') {
return 204;
}
location / {
index index.php ;
}
location ~ \.php(.*)$ {
fastcgi_pass fastcgi_server;
fastcgi_index index.php;
fastcgi_split_path_info ^((?U).+\.php)(/?.+)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
include fastcgi_params;
}
方法二
分别都加上add_header,独立控制2种请求的回复,可以更精细控制。
location / {
add_header 'Access-Control-Allow-Origin' 'http://127.0.0.4:8080';
dd_header 'Access-Control-Allow-Methods' '*';
add_header 'Access-Control-Allow-Headers' 'content-type';
add_header 'Access-Control-Allow-Credentials' 'true';
if ($request_method = 'OPTIONS') {
return 204;
}
index index.php ;
}
location ~ \.php(.*)$ {
add_header 'Access-Control-Allow-Origin' 'http://127.0.0.4:8080';
add_header 'Access-Control-Allow-Methods' '*';
add_header 'Access-Control-Allow-Headers' 'content-type';
add_header 'Access-Control-Allow-Credentials' 'true';
fastcgi_pass fastcgi_server;
fastcgi_index index.php;
fastcgi_split_path_info ^((?U).+\.php)(/?.+)$;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
include fastcgi_params;
}
简单请求
简单请求不会触发CORS 预检,需要满足以下所有条件
- 方法之一
- 除了由用户代理自动设置的标头(例如Connection,User-Agent、 或在 Fetch 规范中定义的其他标头作为禁止的标头名称),允许设置的头是
- Accept
- Accept-Language
- Content-Language
- Content-Type (有限制)
- Content-Type 允许的值
- application/x-www-form-urlencoded
- multipart/form-data
- text/plain
- 如果请求是使用XMLHttpRequest对象发出的,则不会在请求中使用的XMLHttpRequest.upload属性返回的对象上注册事件侦听器;也就是说,给定一个XMLHttpRequest实例xhr,没有代码调用xhr.upload.addEventListener()添加事件监听器来监控上传。
- ReadableStream请求中没有使用任何对象。
参考
Cross-Origin Resource Sharing (CORS)