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

简介: 本文是第2节,紧接上1节 【实战晋级】理解跨域以及工作中跨域问题的处理 - 1。

本文是第2节,紧接上1节 【实战晋级】理解跨域以及工作中跨域问题的处理 - 1。

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


  1. 预检请求的基本概念、处理方式
  2. 预检请求的优化
  3. 上一节中,node 端代码的安全问题在哪里



正文开始


0e862644e5fca3dc502e51c22bb4f62e_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.jpg



场景复现 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

82317d1c78105bfd8684d284f2e58a3d_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

分析问题

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

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

预检请求

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

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

67c5e6fc07ae70c82953545ef285e028_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

解决问题

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

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

b72891920a225b775d5a7a680297d4ab_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

OPTSION 请求

20a4b35e56983f16c32a7d7f8c6ca3d2_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

POST 请求

0f6406d1cdac4c5d5539df4bdaf25eef_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.png

鉴别非简单请求

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

b4998315090e348383561ecd12fe9023_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.jpg


补充说明

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

8feb4fad15e02bbbfc3801fbe61dd222_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.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

834d85c2fbbdd737a62f601afbc7d337_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.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响应头,这个是基础

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

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

预检请求优化

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

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

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

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

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

aaff3e8c573841e8771ec5befcc06322_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.jpg

e0fb5a5e5b45edb179c4ae48e91112f9_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.jpg

15f6a6527f064ba620ff4b5be2bfd225_640_wx_fmt=png&wxfrom=5&wx_lazy=1&wx_co=1.jpg

安全问题不得不提


在第一节的时候我们的 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 交流,另外我创建了一个前端晋级交流群,欢迎你的到来。

目录
打赏
0
0
0
0
4
分享
相关文章
【Shell 命令集合 磁盘管理 】Linux读取、转换并输出数据 dd命令使用教程
【Shell 命令集合 磁盘管理 】Linux读取、转换并输出数据 dd命令使用教程
312 0
Deepseek开源R1系列模型,纯RL助力推理能力大跃升!
近期Deepseek正式发布 DeepSeek-R1,并同步开源模型权重。DeepSeek-R1 遵循 MIT License,允许用户通过蒸馏技术借助 R1 训练其他模型。
2307 25
模型训练数据-MinerU一款Pdf转Markdown软件
MinerU是由上海人工智能实验室OpenDataLab团队开发的开源智能数据提取工具,专长于复杂PDF文档的高效解析与提取。它能够将含有图片、公式、表格等多模态内容的PDF文档转化为Markdown格式,同时支持从网页和电子书中提取内容,显著提升了AI语料准备的效率。MinerU具备高精度的PDF模型解析工具链,能自动识别乱码,保留文档结构,并将公式转换为LaTeX格式,广泛适用于学术、财务、法律等领域。
827 4
【Docker项目实战】使用Docker部署Raneto知识库平台
【2月更文挑战第11天】使用Docker部署Raneto知识库平台
313 2
【Docker项目实战】使用Docker部署Raneto知识库平台
解读阿里云搜索开发工作台如何快速搭建AI语义搜索及RAG链路
本文介绍阿里云搜索开发工作台如何通过内置数据处理、查询分析、排序、效果测评、大模型等服务,结合阿里云搜索引擎及开源引擎,灵活打造AI语义搜索及RAG链路。
20258 15
[gin]简单的gin-mongo
[gin]简单的gin-mongo
阿里云域名价格注册、续费及转入费用(com、cn多域名后缀报价)
阿里云com域名注册价格69元,企业新用户注册com域名优惠价1元;cn域名注册价格29元,新用户注册cn域名8.8元;阿里云com域名续费79元一年,使用优惠口令续费68元一年;阿里云cn域名续费价格39元,使用优惠口令后价格35元一年。
4712 1
阿里云域名价格注册、续费及转入费用(com、cn多域名后缀报价)
阿里泛日志设计与实践问题之SLS Scan的语法该如何定义
阿里泛日志设计与实践问题之SLS Scan的语法该如何定义
【RAG实践】Rerank,让RAG更近一步
本文主要关注在Rerank,本文中,Rerank可以在不牺牲准确性的情况下加速LLM的查询(实际上可能提高准确率),Rerank通过从上下文中删除不相关的节点,重新排序相关节点来实现这一点。
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等

登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问