Agent
View Code
解决方法添加在 参数 后面 canshu+='&'+document.cookie; ,或自定义 header 中,例如 xhr.setRequestHeader("web-cookie","cookie_value");
如果 header 设置放 open 前面提示(原生 js 中 XMLHttpRequest 与 jquery 中的 ajax):
Uncaught DOMException: Failed to execute 'setRequestHeader' on 'XMLHttpRequest': The object's state must be OPENED.
跨域携带 cookie 问题:withCredentials
支持withCredentials属性的浏览器有Firefox 3.5+、Safari 4+和Chrome。IE10及更早版本都不支持。在jQuery1.5中,withCredentials这个属性不在原生的xhr中,所以这个请求会被忽略。
如果在同域下配置 xhr.withCredentials 是无效的,同域下 请求标头 默认携带 Cookie 。跨域时当配置了xhr.withCredentials = true时,必须在后端指定域名,例如: header('Access-Control-Allow-Origin:http://aa.com'); ,而不能指定为*。服务器接收带凭据的请求,需要会用 header('Access-Control-Allow-Credentials:true'); 响应。Credentials必须在前后端都被配置,才能使带credentials的CORS请求成功。
如果发送的是带凭据的请求,但服务器的相应中没有包含这个头部,那么浏览器就不会把相应交给JavaScript(于是,responseText中将是空字符串,status的值为0,而且会调用onerror()事件处理程序)。另外,服务器还可以在Preflight响应中发送这个HTTP头部,表示允许源发送带凭据的请求。
前端获取服务端响应的cookie
1、服务设置向前端公开的header header('Access-Control-Expose-Headers:Set-Cookie')
2、cookie 跨域需要设置
// cookie 启用安全传输
'secure' => true,
// httponly设置
'httponly' => false,
// 是否使用 cookie
'setcookie' => true,
// None || Lax || Strict
'samesite' => 'None'
3、获取服务端数据后,前端获取cookie
1 // js/jquery 取得响应的 cookie + 浏览器本身的cookie,
2 console.log(document.cookie);
3 // js 中 数据请求成功,获取响应头信息
4 console.log(xhr.getAllResponseHeaders())
5 // jquery 中 ajax 也可使用
6 console.log("Cookie: " + response.getResponseHeader("Set-Cookie"));
7 // jquery 中数据获取成功,获取响应头信息
8 console.log(response.getAllResponseHeaders())
第 4 行 与第 8 行 获取 响应头信息,以及 axios 响应拦截器中的 console.log(response.headers); 在同域、跨域下获取的 header 信息相同。
以下是同域下获取的信息,但是没有获取到 set-cookie,原因不知?
access-control-allow-credentials: true
access-control-allow-headers: X-Requested-With,Content-Type,XX-Device-Type,XX-Token,XX-Api-Version,XX-Wxapp-AppId,Authorization,Cookie
access-control-allow-methods: GET,POST,PATCH,PUT,DELETE,OPTIONS
access-control-allow-origin: http://gohosts.com
access-control-expose-headers: Set-Cookie
connection: Keep-Alive
content-type: application/json; charset=utf-8
date: Sat, 04 Feb 2023 06:03:21 GMT
keep-alive: timeout=5, max=99
samesite: None
server: Apache/2.4.23 (Win32) OpenSSL/1.0.2j mod_fcgid/2.3.9
transfer-encoding: chunked
x-powered-by: PHP/7.1.13
在 跨域 下获取的 header 信息 ,我这里使用的是 chrome 浏览器,chrome 没有对 cookie 配置
content-type: application/json; charset=utf-8
同时跨域有客户端兼容问题,导致前端 js 获取不到 set-cookie,未测试:
跨域cookie失效问题 SameSite=None和secure
Chrome 配置samesite=none方式
Cookie中的SameSite设置
聊聊Cookie的SameSite属性
4、建议不使用cookie 跨域,可以传递指定参数
相关文章:
JavaScript中的AJAX请求
XMLHttpRequest参数详解
options 预检请求
前端 ajax 有时会发送2次请求,是因为使用了带预检(Preflighted)的跨域请求。先发送一个OPTIONS请求,这个请求叫Preflighted Request(带预检的跨域请求)。预检请求会检测服务器是否支持我们的真实请求所需要的跨域资源,唯有资源满足条件才会发送真实的请求。
如果options获得的回应是拒绝性质的,比如404\403\500等http状态,就会停止post、get等请求的发出。或者前端请求头部增加了authorization项,那么在服务器响应头中需要放入Access-Control-Allow-Headers,Access-Control-Allow-Headers的值中必须要包含authorization,否则OPTIONS预检会失败,从而导致不会发送真实的请求。
以下情况下请求会发送 options 预检请求
// 标号前 * 表示常用
*1. 请求方法不是`GET/HEAD/POST`;
2. HTTP请求头限制这几种字段,`人为设置该集合之外 `的其他首部字段:
`{Accept、Accept-Language、Content-Language、
Content-Type(需要注意额外的限制)、
DPR、Downlink、Save-Data、Viewport-Width、Width}`;
*3. POST请求的`Content-Type`并非其中之一:
application/x-www-form-urlencoded,
multipart/form-data,
text/plain
4. 请求中的任意 `XMLHttpRequestUpload` 对象均有注册事件监听器;
*5. 请求设置了自定义的 `header` 字段;
6. 请求中没有使用 `ReadableStream` 对象;
服务端跨域设置
1、必须在 header 中设置 Access-Control-Allow-Origin 的域名,不可设置为 *
2、必须在 header 中设置 Access-Control-Allow-Credentials 为 true
方法一:PHP 文件设置跨域
public function handle($request, \Closure $next)
// 前端 请求标头 信息设置
// 跨域问题 允许访问的域名 ,如果携带cookie 不可为 *
$host_url="http://gohosts.com";
header('Access-Control-Allow-Origin:'.$host_url);
// 对请求的响应允许暴露前端的js,服务端使用session 存储,session 是依赖于 cookie,所以前端必须允许携带 cookie
header('Access-Control-Allow-Credentials:true');
// 自定义向前端 公开的响应头
header('Access-Control-Expose-Headers:Set-Cookie');
header('Access-Control-Allow-Headers:X-Requested-With,Content-Type,XX-Device-Type,XX-Token,XX-Api-Version,XX-Wxapp-AppId,Authorization,Cookie');
header('Access-Control-Allow-Methods:GET,POST,PATCH,PUT,DELETE,OPTIONS');
//跨域请求中设置了自定义的header字段, 所以该请求是preflighted request, 则请求前一定会发送一个OPTIONS作为预请求.
if(strtoupper($request->method())== 'OPTIONS'){
exit;
return $next($request);
这个文件使用得 thinkphp 框架,当前文件为中间件。
方法二:nginx 配置跨域
location / {
index index.php;
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' 'http://odocker.com';
// 用来指定本次预检请求的有效期,单位为秒,在此期间不用发出另一条预检请求。 如果值为 -1,则表示禁用缓存
add_header 'Access-Control-Max-Age' 86400;
// 对请求的响应允许暴露前端的js
add_header 'Access-Control-Allow-Credentials' 'true';
add_header 'Access-Control-Allow-Headers' 'Authorization,Cookie,Content-Type,Accept,Origin,User-Agent,DNT,Cache-Control,X-Mx-ReqToken,X-Requested-With';
add_header 'Access-Control-Allow-Methods' 'GET,POST,OPTIONS'
add_header 'Content-Length' 0;
// 服务器成功处理了请求,但没返回任何内容。
return 204;
if (!-e $request_filename) {
rewrite ^/(.*)$ /index.php?s=$1 last;
方法三:apache下修改vhosts中根域名的配置,需要重启 apache
<Directory "/Users/cindy/dev">
AllowOverride ALL
Header set Access-Control-Allow-Origin https://www.google.com,https://www.baidu.com
</Directory>
方法四:修改.htaccess配置文件
SetEnvIf Origin "^http(s)?://(.+\.)?(submit.magazine.ubandev.com|localhost:8080)$" origin_is=$0
Header always set Access-Control-Allow-Origin %{origin_is}e env=origin_is
Header set Access-Control-Allow-Credentials true>
优点:无需修改apache域名配置。静态文件也可设置响应头,可以跨域。正则之后响应头只有一个域名,可以发送cookie。本人未测试。
方法五:修改apache/conf/httpd.conf 文件,需要重启 apache
找到 #LoadModule headers_module modules/mod_headers.so,把#注释符去掉,目的是开启apache头信息自定义模块
缺点:安全性缺失,谁都能访问。相当于完全放弃跨域控制,且无法发送登陆凭证,发送cookie等依然会被拦截。本人未测试。
服务器配置
如果前端使用了 Authorization ,服务端(apache)需要配置, 在根目录创建 .htaccess 文件
// 第一种方法
# Authorization Headers
RewriteCond %{HTTP:Authorization} ^(.+)$
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
// 第二种方法
<IfModule mod_rewrite.c>
SetEnvIf Authorization .+ HTTP_AUTHORIZATION=$0
</IfModule>