【实战晋级】理解跨域以及工作中跨域问题的处理 - 2 预检请求

开门见山

本文是第2节,紧接上1节 

这个时代每个人的时间都很宝贵,为了不浪费读者的时间,需要读者自测是否需要阅读本文,如果以下问题你都 ok,那你完全可以 break了。

  1. 预检请求的基本概念、处理方式

  2. 预检请求的优化

  3. 上一节中,node 端代码的安全问题在哪里

正文开始

640?wx_fmt=png

场景复现 1

用 post或者 get 发送json数据, 结果控制台报如下错误。

准备工作

  • 解决 Access-Control-Allow-Origin问题,这个是基础

  • 将请求改为发送 json

function xhrSend() {	
    var xhr = new XMLHttpRequest();   //创建对象	
    xhr.open('POST', 'http://localhost:8102/getdata', true);	
    xhr.withCredentials=true;	
    - xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');	
    + xhr.setRequestHeader('Content-Type', 'application/json');	
    xhr.onreadystatechange = function () {	
        console.log('state change', xhr.readyState);	
        if (xhr.readyState == 4) {	
            console.log(xhr.responseText);	
        }	
    }	
    xhr.send('a=1&b=2');//发送数据	
}

错误复现

请求被阻止,需要在响应求头 Access-Control-Allow-Headers内设置 content-type

640?wx_fmt=png

分析问题

为什么在需要设置这个响应头呢?

因为发送json 数据,并且设置了请求头 content-type:application/json,就不再是简单请求,而是非简单请求,需要服务器进一步做处理。

预检请求

非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight)。

浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。

640?wx_fmt=png

解决问题

根据提示设置响应头 Access-Control-Allow-Headers:content-type

可以看到下面发送了两次请求,一次OPTIONS,一次 POST

640?wx_fmt=png

OPTSION 请求

640?wx_fmt=png

POST 请求

640?wx_fmt=png

鉴别非简单请求

不能同时满足下面两个条件的请求,就属于非简单请求

640?wx_fmt=png

补充说明

如果想在请求中设置自定义请求头

640?wx_fmt=png

同样的方法在服务器端设置响应头即可,也可以设置多个值,用逗号间隔。

        ctx.set('Access-Control-Allow-Headers', 'content-type,x-custom-header');

场景复现 2

我想用 PUT 方法发送请求。

    xhr.open('PUT', 'http://10.70.65.235:8100/getdata', true);

复现问题

提示请求被阻止,PUT 方法是禁止的,需要设置响应头 Access-Control-Allow-Methods

640?wx_fmt=png

解决问题

  • 解决 Access-Control-Allow-Origin问题,这个是基础

根据我们对非简单请求的理解,可以判断本次请求也是需要发一次预检请求。

//跨域处理	
app.use((ctx) => {	
    //指定一个接口和返回数据	
    var path =ctx.path;	
    if(path==='/getdata'){	
        console.log('receive req');	
        //服务端通过 ctx.headers.origin 获取请求中的origin	
        ctx.set('Access-Control-Allow-Origin', ctx.headers.origin);	
        + ctx.set('Access-Control-Allow-Methods', 'PUT');	
        ctx.body=JSON.stringify({	
            code:0,	
            msg:'success',	
            data:[]	
        });	
    }else{	
        ctx.body='welcome';	
    }	
});

套路总结

根据上面的几个实例,基本能总结出一些套路,正常通信的建立基本上都是服务端需要来进行调整,设置响应的响应头即可。

简单请求和非简单请求都要首先设置 Access-Control-Allow-Origin响应头,这个是基础

    ctx.set('Access-Control-Allow-Origin', ctx.headers.origin);

然后根据我们对非简单请求的理解以及控制台提示错误进行分析和处理。

预检请求优化

如果一个请求是预检请求,那么就需要和服务器通信两次,每次都多了一次请求这有点浪费啊。

不过这个问题是可以优化的。

设置 Access-Control-Max-Age,这个字段不是必须的,表示用来指定本次预检请求的有效期,单位-秒。

下面设置预检请求的有效期为60分钟,时间过后将会重新发送预检请求。

 ctx.set('Access-Control-Max-Age', 3600);

640?wx_fmt=png

640?wx_fmt=png

640?wx_fmt=png

安全问题不得不提

在第一节的时候我们的 node 端代码存在一个问题,这段代码设置了响应头的值。

 ctx.set('Access-Control-Allow-Origin', ctx.headers.origin);//问题在这里

上面代码不难看出,虽然可以正常运行解决跨域问题,但是若在线上运行的话就有很大的问题,会导致任何人在浏览器环境都能访问此接口,正常的情况应该会有一个白名单配置,在白名单内的域名才能访问此接口。

   if (canRequest(ctx.headers.origin)){	
        //服务端通过 ctx.headers.origin 获取请求中的origin	
            ctx.set('Access-Control-Allow-Origin', ctx.headers.origin);	
   }

最后

本小节到这里就介绍完了,简单请求和预检请求的跨域处理你了解了吗?

如果有问题可以加我的微信: 223344386 交流,另外我创建了一个前端晋级交流群,欢迎你的到来。

本节源码已上传github

https://github.com/Bigerfe/fe-learn-code-guide/tree/master/src/cors-demo

理论知识参考

http://www.ruanyifeng.com/blog/2016/04/cors.html

更多精彩、好玩、有用的前端内容,请关注公众号《前端张大胖》

前端晋级交流群已建好

加wx223344386 (备注进群)

640?wx_fmt=png

码字不易,请多鼓励
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zz_jesse

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值