这跨域请求真的不能带cookie

1,106 阅读4分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第10天,点击查看活动详情

故事背景

昨天温习了一下跨域问题,因为自己做demo,怎么写就怎么对,处理跨域问题真实信手拈来,so 一贼,可能是生活看不惯嚣张跋扈的人,于是下午后端老表就来找我联调一个接口。 因为系统要做海外环境还有一些乱七八糟的环境,现在前端要在当前环境,请求不同环境(不同环境不同域名)请求数据,我看了一下,这个复杂了,复杂请求发送了options请求,你要处理一下options请求,设置允许跨域的一系列响应头


       "Access-Control-Allow-Origin": req.headers.origin||req.headers.referer,
       "Access-Control-Allow-Methods": "POST",
       'Access-Control-Allow-Headers': ["xxx"],
       "Access-Control-Allow-Credentials": true

中间太多曲折,但是因为他本地启动的是http服务,我在https里请求,所以一直进不到他的断点。这个问题忽略,纯人为造成的,跳过这个问题, options请求处理完,果然可以请求成功了,但是结果还是不如预期,因为sesssion鉴权存在cookie里,所以请求要携带cookie,否则就会被重定向。

我以为,这些都是意料之中

axios请求跨域携带cookie设置 axios.defaults.withCredentials = true; 这个我真知道,网上搜索也一搜就有,所以这个早就配了,后端配置响应header"Access-Control-Allow-Credentials": true,也配了。但是请求头里迟迟不见cookie的身影,我懵了,说的贼好听,跨域请求携带cookie,真的就能带cookie吗?实际是不可以的,

optons请求是哪里来的,这个没有异议,复杂请求会先发送一个OPTIONS请求,就是探探虚实,看看服务器,允许当前请求访问不, xhr请求分为简单请求复杂请求, 满足下面两个条件就是简单请求

1.请求方法是以下三种方法之一: HEAD GET POST
2.HTTP的头信息不超出以下几种字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三个值:application/x-www-form-urlencoded、multipart/form-data、text/plain

发现问题1 axios这个库不简单,当没有发送数据时,自动过滤了中headers: { "Content-Type": "application/json", },避免了一个简单请求,因为用户错误操作,变成一个复杂请求,避免一次不必要的预检请求 index.html 用live-server启动,端口5500

<!DOCTYPE html>
<html lang="en">
 <head>
   <meta charset="UTF-8" />
   <meta http-equiv="X-UA-Compatible" content="IE=edge" />
   <meta name="viewport" content="width=device-width, initial-scale=1.0" />
   <title>Document</title>
 </head>
 <body></body>


 <script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.27.2/axios.min.js"></script>
 <script>
   axios.defaults.withCredentials = true;
   axios({
     url: "http://localhost:5501/data",
     method: "POST", 
     headers: {
       "Content-Type": "application/json",
     },
   }).then((res) => {
     console.log(res);
   });
   fetch("http://localhost:5501/data", {
     method: "POST", 
     credentials: "include",
     headers: {
       "Content-Type": "application/json",
     },
   })
     .then((response) => response.json())
     .then((res) => {
       console.log(res);
     });

 </script>
</html>

node.js ./server.js

const fs = require('fs');
const http = require('http');
const server = http.createServer(async (req, res) => {
   const {
       url,
       method,
   } = req;
   let data = null;
   if (url == "/data" && method == "POST" || url == '/data' && method == "OPTIONS")
       switch (url) {
           case '/data':
               data = `{
                   "name":"tom",
                   "age":19
               }`
               res.writeHead(200, {
                   "Access-Control-Allow-Methods": "POST",
                   "Access-Control-Allow-Credentials": true,
                   "Access-Control-Allow-Origin": "http://127.0.0.1:5500",
                   "Access-Control-Allow-Headers": 'Content-Type'

               });
               break;
       }
   res.end(data);
})
server.listen('5501', () => {
   console.log('http://localhost:5501')
})

小小的关怀,大大的感动,对axios说声感谢,可能还有其他优化,这里也不测试,也不研究了。毕竟是锦上添花的东西 请求头里没有content-type,所以是简单请求,没有预检请求

image.png

image.png

如果axios加了data

    axios({
     url: "http://localhost:5501/data",
     method: "POST", 
     data:{
       name:"xx"
     },
     headers: {
       "Content-Type": "application/json",
     },
   }).then((res) => {
     console.log(res);
   });

就真的是复杂请求了,没法优化了

image.png

重点来了 生产中跨域请求不可以携带cookie,暂时没有解决办法,chrome安全机制

携带cookie了吗?并没有。chrome不可以

image.png

Safari可以携带cookie,也没有预检请求 image.png 当前的url,请求另一个url不可携带cookie,cookie是按domain区分的,也就是按域名区分,如果把请求的url中loaclhost改成127.0.0.1,就可以携带cookie

image.png

谷歌浏览器Chrome 80版本默认SameSite导致跨域请求Cookie丢失_php_PHP面试网

在Chrome 80版本中,Chrome会将没有声明SameSite值的cookie默认设置为SameSite=Lax。只有采用SameSite=None; Secure设置的cookie可以从外部访问,前提是通过安全连接(即HTTPS)访问 暂时没验证