文档章节

Ajax 跨域(CORS)请求中的预检请求

IamOkay
 IamOkay
发布于 2016/05/10 07:10
字数 1006
阅读 1780
收藏 37

关于预检请求

定义:预检请求(Preflighted requests )是浏览器发起跨域请求时,通过OPTIONS方法询问服务器对跨域请求的支持情况(支持的包含请求方法、请求头、数据类型)。

触发预检请求的三类条件

  1. 默认情况下,跨域请求只支持GET,HEAD,POST方法,如果不是这三个请求方法(比如:PUT、DELETE、CONNECT、OPTIONS、TRACE和PATCH),那么将触发预检请求

  2. 默认情况下,浏览器跨域请求时,会自动添加的请求头(HOST,Referer,Connection、Accept、User-Agent,Accept-Languange,Accept-Encoding,Accept-Charset和Content-Type),这些请求中还有其他请求头时,那么将触发预检请求。

  3. 如1、2所说的情况排除在外的条件下,跨域请求是,浏览器支持的Content-Type值为application/x-www-form-urlencoded,multipart/form-data和text/plain。如果是其他数据类型(如application/json,text/xml...),那么将触发预检请求。

下面通过一个Ajax跨域请求来验证

var xhr= new XMLHttpRequest();
var url = 'http://bar.other/resources/post-here/';
var body = '<?xml version="1.0"?><person><name>Arun</name></person>';
function callOtherDomain(){
  if(invocation)
    {
      xhr.open('POST', url, true);
      xhr.setRequestHeader('X-PINGOTHER', 'pingpong'); //自定义的Header
      xhr.setRequestHeader('Content-Type', 'application/xml'); //特殊的文档类型
      xhr.onreadystatechange = function(){};
      xhr.send(body); 
}
}

满足以上之一,便可发起预检请求,预检请求流程如下

OPTIONS /resources/post-here/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Origin: http://foo.example
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER, Content-Type


HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://foo.example
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400
Vary: Accept-Encoding, Origin
Content-Encoding: gzip
Content-Length: 0
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Content-Type: text/plain

POST /resources/post-here/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
X-PINGOTHER: pingpong
Content-Type: text/xml; charset=UTF-8
Referer: http://foo.example/examples/preflightInvocation.html
Content-Length: 55
Origin: http://foo.example
Pragma: no-cache
Cache-Control: no-cache

<?xml version="1.0"?><person><name>Arun</name></person>


HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:40 GMT
Server: Apache/2.0.61 (Unix)
Access-Control-Allow-Origin: http://foo.example
Vary: Accept-Encoding, Origin
Content-Encoding: gzip
Content-Length: 235
Keep-Alive: timeout=2, max=99
Connection: Keep-Alive
Content-Type: text/plain

[Some GZIP'd payload]

 

我们看到,首次发起的是OPTIONS请求,因为OPTIONS请求的作用本身就是询问服务器的请求,他这里询问浏览器是否支持如下条件请求

Access-Control-Request-Method: POST  
#是否支持POST
Access-Control-Request-Headers: X-PINGOTHER, Content-Type  
#是否支持X-PINGOTHER自定义请求头的内容,Content-Type可能是其他值,因此有必要询问

 

服务器回应是

Access-Control-Allow-Origin: http://foo.example
#支持foo.example域
Access-Control-Allow-Methods: POST, GET, OPTIONS
#支持的方法POST,GET,OPTIONS,实际上OPTIONS本身就支持
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type 
#支持的请求头,Content-Type是特殊的类型时,会触发预检,因此,这里最好加上Content-Type
Access-Control-Max-Age: 86400
#支持的缓存时间

如果满足以上条件,浏览器会自动发起提交之前没提交的数据,否则拒绝提交数据。

 

关于withCredentials

在跨域请求中,类似Cookie等敏感信息一般不会跨域传输,但是在服务器允许的情况下,Cookie会被发送

注意:Cookie的发送需要服务器允许才行,此外,跨域js所处的环境必须是线上环境【服务器环境】

Access-Control-Allow-Credentials: true

浏览器也要允许

var xhr= new XMLHttpRequest();

var url = 'http://bar.other/resources/post-here/';
var body = '<?xml version="1.0"?><person><name>Arun</name></person>';

function callOtherDomain(){
  if(invocation)
    {
      xhr.withCredentials = true;#允许cookie信息
      xhr.open('POST', url, true);
      xhr.setRequestHeader('X-PINGOTHER', 'pingpong'); //自定义的Header
      xhr.setRequestHeader('Content-Type', 'application/xml'); //特殊的文档类型
      xhr.onreadystatechange = function(){};
      xhr.send(body); 
}
}

 

服务器设计建议

服务器设计,我们不仅要处理常见的跨域请求,对于Preflighted  Request请求,我们更应该保证浏览器能得到预检请求的结果,因此,服务器端一定要处理OPTIONS请求

 

© 著作权归作者所有

IamOkay

IamOkay

粉丝 200
博文 483
码字总数 403074
作品 0
海淀
程序员
私信 提问
加载中

评论(2)

xcorp
xcorp
谢谢分享
hylent
hylent
mark
跨域、跨域cookie共享 CORS 详解

跨域的问题在前端是一个说起来都觉得要说烂的话题,可是到底有没有真正了解,有必要检查一下对 CORS的了解。 一、什么是CORS? CORS是一个W3C标准,全称是“跨域资源共享(Cross-origin resou...

王双肖
2018/03/22
0
0
同源策略与CORS

同源策略 它是浏览器最核心也是最基本的安全功能,浏览器的同源策略,限制了来自不同的 “document” 或脚本对当前的 “document” 的读取或设置某些属性 如果没有同源策略,可能 a.com 的一...

林塬
2017/12/29
0
0
详解跨域(最全的解决方案)

image.png 1. 什么是跨域 跨域,是指浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对JavaScript实施的安全限制。 同源策略限制了一下行为: Cookie、LocalStorage ...

极客教程
2017/12/13
0
0
springboot 跨域配置cors

1 跨域的理解 跨域是指:浏览器A从服务器B获取的静态资源,包括Html、Css、Js,然后在Js中通过Ajax访问C服务器的静态资源或请求。即:浏览器A从B服务器拿的资源,资源中想访问服务器C的资源。...

Vincent-Duan
05/30
0
0
.NET Core API CORS

最近参与一个前后端分离的项目,后端基于 .NET Core 2.1 开发,在进行前后端对接的过程中,被跨域问题折腾得有点脾气了,这里把经验和大家分享一下。 GET/POST 请求 在服务端不做任何调整的情...

BeckJin
2018/08/04
0
0

没有更多内容

加载失败,请刷新页面

加载更多

聊聊dubbo的TimeoutFilter

序 本文主要研究一下dubbo的TimeoutFilter ListenableFilter dubbo-2.7.2/dubbo-rpc/dubbo-rpc-api/src/main/java/org/apache/dubbo/rpc/ListenableFilter.java public abstract class Liste......

go4it
33分钟前
5
0
方法与数组

方法 方法就是完成特定功能的代码块;在很多语言里面都有函数的定义,函数在Java中被称为方法 格式: 修饰符 返回值类型 方法名(参数类型 参数名1,参数类型 参数名2…) throw 异常{ 函数体;...

凹凸凸
56分钟前
4
0
死磕 java同步系列之StampedLock源码解析

问题 (1)StampedLock是什么? (2)StampedLock具有什么特性? (3)StampedLock是否支持可重入? (4)StampedLock与ReentrantReadWriteLock的对比? 简介 StampedLock是java8中新增的类,...

彤哥读源码
今天
10
1
性能优化工具(二)-Systrace

一、简介 Systrace是分析Android性能问题的神器,Google IO 2017上更是对其各种强推. 是分析卡顿掉帧问题核心工具,只要能提供卡顿现场,systrace就能很好定位问题,但是有一定上手难度,所以...

天王盖地虎626
今天
9
0
Linux 网络

MtrS
今天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部