当前位置: 首页 > news >正文

前端CORS请求梳理

前后端分离来说,跨域请求是我们第一个需要解决的问题。下面是我在开发中总结出来的一些经验。

开发中,很多时候会出现Options请求CORS预检请求),但是有的时候又不会出现。某些请求不会触发 CORS 预检请求,这样的请求被称为简单请求,其他的请求被称为非简单请求。首先我们来区分简单请求和非简单请求。

一、简单请求和非简单请求

浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。
只要同时满足以下两大条件,就属于简单请求。

1、请求方法是以下三种方法之一:

HEADGETPOST

2、HTTP的头信息不超出以下几种字段:

Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三个值application/x-www-form-urlencodedmultipart/form-datatext/plain
凡是不同时满足上面两个条件,就属于非简单请求。浏览器对这两种请求的处理,是不一样的。

二、和跨域有关的头部梳理

现在我们知道我们哪些请求是简单请求哪些是非简单请求,上面有提到HTTP头部和CORS跨域请求,CORS全称Cross-origin resource sharing,也就是跨域资源共享,浏览器出于安全角度考虑限制跨域HTTP请求,这就是同源策略,所以后端需要设置请求头部才能允许跨域。

1、Access-Control-Allow-Methods:

是逗号分隔的一个字符串,表明服务器允许的跨域请求的方法

2、Access-Control-Allow-Headers:

是一个逗号分隔的字符串,表明服务器支持的所有头信息字段,不限于浏览器在”预检”中请求的字段。

3、Access-Control-Allow-Credentials:

该字段表示是否可以将对请求的响应暴露给页面,一般来说是cookieCredentials必须在前后端都被配置才能使带credentials的CORS请求成功jQuery可以通过设置xhrFields: {withCredentials:true}promise可以通过设置credentials: 'include'

4、Access-Control-Max-Age:

用来指定本次预检请求的有效期,单位为秒。

5、Access-Control-Allow-Origin:

表示资源是否被允许与给定的origin共享

6、Access-Control-Expose-Headers:

响应首部 Access-Control-Expose-Headers 列出了哪些首部可以作为响应的一部分暴露给外部。默认情况下,只有六种 simple response headers (简单响应首部)可以暴露给外部:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如果想要让客户端可以访问到其他的首部信息,可以将它们在 Access-Control-Expose-Headers 里面列出来。

7、Access-Control-Request-Headers:

请求首部 Access-Control-Request-Headers 出现于 preflight request (预检请求)中,用于通知服务器在真正的请求中会采用哪些请求首部

8、Access-Control-Request-Method:

请求首部 Access-Control-Request-Method 出现于 preflight request (预检请求)中,用于通知服务器在真正的请求中会采用哪种 HTTP 方法。因为预检请求所使用的方法总是 OPTIONS ,与实际请求所使用的方法不一样,所以这个首部是必要的。

三、发送cookie

如果需要发送cookie,前后端都被配置,前端需要设置jQuery可以通过设置xhrFields: {withCredentials:true},promise可以通过设置credentials: 'include'
服务器端需要设置res.setHeader('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’.

需要注意的是,如果要发送Cookie,Access-Control-Allow-Origin就不能设为星号,必须指定明确的、与请求网页一致的域名。

同时,Cookie依然遵循同源政策,只有用服务器域名设置的Cookie才会上传,其他域名的Cookie并不会上传,且(跨源)原网页代码中的document.cookie也无法读取服务器域名下的Cookie。
这时候浏览器会报错

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’.

*我们来看看node如何不使用如何插件和框架来解析cookie
,下面是代码:

//解析cookie的函数

function parseCookies (request) {    
    let list = {},
    rc = request.headers.cookie;

    rc && rc.split(';').forEach(function( cookie ) {        
        let parts = cookie.split('=');
        list[parts.shift().trim()] = decodeURI(parts.join('='));
    });    
    return list;
}
http.createServer(function (request, response) {    
    //读取cookie
    var cookies = parseCookies(request);
    //写入cookie
    response.writeHead(200, {            
        'Set-Cookie': 'mycookie=test',            
        'Content-Type': 'text/plain'
    });
    response.end('Hello World\n');}).listen(8124);
})
复制代码

四、Content-Type的值及其作用

对接后端的接口的时候,Content-Type的值是决定后端那边怎么去解析我们的传参的。Content-type常用几个值:

1.text/html
2.text/plain
3.text/css
4.text/javascript
5.application/x-www-form-urlencoded
6.multipart/form-data
7.application/json
8.application/xml

前面几个都很好理解,都是html,css,javascript的文件类型,后面四个是POST的发包方式

1、application/x-www-form-urlencoded

html中表单提交的默认格式,jquery ajax请求默认的content-type默认也是这种格式,并且jquery会把data:{foo1:”bar1”,foo2:”bar2”}数据转换成key1=value1&key2=value2,可以通过processData来关闭是否提前处理数据,数据格式是key1=value1&key2=value2形式。

下面是jquery做data预处理的代码,默认processData为true,所以如果data有值就会进入判断就会把json格式转化为key1=value1&key2=value2的格式

if ( s.data && ( s.processData || typeof s.data === "string" ) ) {
    cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data;
    
    // #9682: remove data so that it's not used in an eventual retry
    delete s.data;
}复制代码

2、multipart/form-data

multipart/form-data用在发送文件的POST包。
这里Content-Type告诉我们,发包是以multipart/form-data格式来传输,另外,还有boundary用于分割数据。
当文件太长,HTTP无法在一个包之内发送完毕,就需要分割数据,分割成一个一个chunk发送给服务端,
那么—用于区分数据快,而后面的数据sqe6Nhq4gtMfHLOY 就是标示区分包作用。

------WebKitFormBoundarysqe6Nhq4gtMfHLOY
Content-Disposition: form-data; name:"UserWxCode"

123
------WebKitFormBoundarysqe6Nhq4gtMfHLOY
Content-Disposition: form-data; name="CodeType"

Public
------WebKitFormBoundarysqe6Nhq4gtMfHLOY--复制代码

3、application/json

发送请求的时候需要JSON.stringify一下,HTTP通信中并不存在所谓的json,而是将string转成json罢了,也就是,application/json可以将它理解为text/plain,普通字符串

4、text/xml和application/xml

text/xml忽略xml文件头中的关于编码的设定(<?xml version=”1.0” encoding=”UTF-8”?>),默认采用us-ascii编码。 application/xml会依照xml文件头中编码的设定推荐使用application/xml

五、fetch和jquery Ajax设置Headers,cookies

//fetch设置Headers,cookies

//方式1
let myHeaders = new Headers({    
   'Content-Type': 'application/json; charset=UTF-8',    
   'token': 123
});

//方式2
headers: {    
   'Content-Type': 'application/json; charset=UTF-8',    
   'token': 123
}

//发送cookies:
credentials: 'include'

//jquery ajax设置Headers,cookies

//设置header方式一
headers: {
   UserName: 'zxplus',
   EncryptKey: '1111'
},

//方式二
beforeSend: function(request) {
    request.setRequestHeader("UserName", "zxplus");
},
//发送cookie
xhrFields: {
   withCredentials:true //支持附带详细信息
},复制代码

参考

https://stackoverflow.com/questions/3393854/get-and-set-a-single-cookie-with-node-js-http-server
http://www.ruanyifeng.com/blog/2016/04/cors.html
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS
https://segmentfault.com/a/1190000006039533
http://www.cnblogs.com/caoshiqing/p/6825608.html
http://homeway.me/2015/07/19/understand-http-about-content-type/


相关文章:

  • osquery简单试用
  • 关于Java中分层中遇到的一些问题
  • 156:Ananagrams
  • 区块链技术
  • 浅度理解NodeJS的HTTP模块
  • Git的本地仓库与GitHub的远程仓库
  • haproxy+pacemaker高可用负载均衡
  • 剖析RAC中的@weakify、@strongify
  • 解析PE资源表与重定位表
  • BTA | 周政军:区块链中侧链和分片解决不了的扩容问题,交给DAG吧!
  • PHP定时任务Crontab结合CLI模式详解
  • go append函数以及写入
  • mysql错误Table ‘./mysql/proc’ is marked as crashed and should be repaired
  • 于小镭:区块链将从三方面带来颠覆性认知革命
  • xtrabackup备份和还原
  • 时间复杂度分析经典问题——最大子序列和
  • 【前端学习】-粗谈选择器
  • 2019.2.20 c++ 知识梳理
  • Angular4 模板式表单用法以及验证
  • css布局,左右固定中间自适应实现
  • Go 语言编译器的 //go: 详解
  • java小心机(3)| 浅析finalize()
  • PHP 7 修改了什么呢 -- 2
  • Python利用正则抓取网页内容保存到本地
  • SpiderData 2019年2月23日 DApp数据排行榜
  • SQLServer之创建显式事务
  • Terraform入门 - 3. 变更基础设施
  • Xmanager 远程桌面 CentOS 7
  • 关于for循环的简单归纳
  • 基于遗传算法的优化问题求解
  • 原生 js 实现移动端 Touch 滑动反弹
  • 自制字幕遮挡器
  • 摩拜创始人胡玮炜也彻底离开了,共享单车行业还有未来吗? ...
  • ​软考-高级-信息系统项目管理师教程 第四版【第19章-配置与变更管理-思维导图】​
  • #Z0458. 树的中心2
  • #我与Java虚拟机的故事#连载12:一本书带我深入Java领域
  • (1)Nginx简介和安装教程
  • (Mac上)使用Python进行matplotlib 画图时,中文显示不出来
  • (Matlab)遗传算法优化的BP神经网络实现回归预测
  • (第27天)Oracle 数据泵转换分区表
  • (附源码)ssm失物招领系统 毕业设计 182317
  • (一)spring cloud微服务分布式云架构 - Spring Cloud简介
  • (已更新)关于Visual Studio 2019安装时VS installer无法下载文件,进度条为0,显示网络有问题的解决办法
  • (转)Google的Objective-C编码规范
  • (转)Java socket中关闭IO流后,发生什么事?(以关闭输出流为例) .
  • * CIL library *(* CIL module *) : error LNK2005: _DllMain@12 already defined in mfcs120u.lib(dllmodu
  • ..thread“main“ com.fasterxml.jackson.databind.JsonMappingException: Jackson version is too old 2.3.1
  • .Net Core/.Net6/.Net8 ,启动配置/Program.cs 配置
  • .Net Web项目创建比较不错的参考文章
  • .NET/C# 在 64 位进程中读取 32 位进程重定向后的注册表
  • .NET6 开发一个检查某些状态持续多长时间的类
  • .net安装_还在用第三方安装.NET?Win10自带.NET3.5安装
  • .NET面试题(二)
  • .NET设计模式(2):单件模式(Singleton Pattern)
  • .pop ----remove 删除