http跨域时的options请求
1、背景
在前后端分离的项目中经常会遇到跨域请求的问题,如果没有进行跨域配置,会浏览器请求失败。我一般采用两种解决方案:
1、采用nginx进行转发,是前后端服务处于同一个域下面,从根本上避免跨域问题。
2、后端服务做一些配置,允许请求跨域,从而解决浏览器跨域问题。但是有时候浏览器还会发送OPTIONS请求。
2、跨域请求
跨域请求的介绍,以及处理方式可以看https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS,说的非常详细
简单说就是,浏览器地址栏中的的域和即将加载的请求的域不是同一个,比如域名或端口不同,浏览器就会把这个当成跨域请求,如果服务端没有正确的返回对应的响应头,那么请求就会被拦截。导致请求失败。
3、两种跨域请求方式
浏览器将CORS请求分为两类:简单请求(simple request)和需要预检的请求(Preflighted requests),这两种方式有什么区别?
简单请求不会发送CORS preflight,也就是正式请求前不会发送OPTIONS请求,而是添加必要的请求头后直接发送请求。必须同时满足以下几个要求才能称之为简单请求:
- 请求头必须是下面三个中的一个:
- 除了浏览器自动追加的一些头 (比如,
Connection,User-Agent, 或者其他“Forbidden header name”), 其他能够添加的头只能是下面中的几个:AcceptAccept-LanguageContent-LanguageContent-Type(but note the additional requirements below)DPRDownlinkSave-DataViewport-WidthWidth
Content-Type 头仅允许以下内容:application/x-www-form-urlencodedmultipart/form-datatext/plain
- No event listeners are registered on any
XMLHttpRequestUploadobject used in the request; these are accessed using theXMLHttpRequest.uploadproperty. - No
ReadableStreamobject is used in the request.
不满足上面条件的跨域请求都称为需要预检的请求,请求前都会先发送OPTIONS请求。
如下面得列子,这个跨域请求就是简单请求,满足上面提到得几个条件。
由于是跨域请求,浏览器追加了Origin头,表示当前浏览器地址上面的域是http://foo.example。响应中多了Access-Control-Allow-Origin头,表示允许访问的域,*表示允许所有的域访问。如果服务端没有这个返回这个响应头,或者响应头中值不包含Origin中的域,浏览器就放弃这个响应。
GET /resources/public-data/ 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
Referer: http://foo.example/examples/access-control/simpleXSInvocation.html
Origin: http://foo.example HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 00:23:53 GMT
Server: Apache/2.0.61
Access-Control-Allow-Origin: *
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/xml
4、预检的请求(Preflighted requests)
不是简单请求,浏览器在跨域请求前都会发送预检,主要是把即将要进行的跨域请求的信息发送给服务端,看服务端受否支持,如果支持,则发送对应的响应头,这时才正式发送跨域请求。
例如下面的预检请求,除了发送Origin头外,还发送了Access-Control-Request-Method和Access-Control-Request-Headers,用来告诉服务端,接下来的跨域请求是post,携带了简单请求外的一些头X-PINGOTHER和Content-Type。如果服务端允许此次跨域请求,那么就需要合理的响应OPTIONS请求,如:
Access-Control-Allow-Origin: http://foo.example 允许http://foo.example的域的请求
Access-Control-Allow-Methods: POST, GET, OPTIONS 支持跨域的方法有这三个
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type 支持跨域的头有
Access-Control-Max-Age: 86400
浏览器收到响应后,如果响应满足那么则正式发送跨域请求。
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
接着看预检请求之后的请求,和简单请求一致,请求头多了Origin,响应头多了Access-Control-Allow-Origin。从这可以看出,非简单请求会发送预检请求,之后再发送正式请求,正式请求和简单请求的跨域头一致。
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
http跨域时的options请求的更多相关文章
- 前后端分离开发,跨域时jsessionid每次请求都变化的问题解决方法
本解决方法的使用前提是,前端开发使用的是vue,后端使用java(SpringMVC) 在前后端分离开发过程中,可能会出现因跨域而导致每次请求的jsessionid不一致的情况 解决方法: 前端:要在 ...
- 当跨域时,js ajax 请求出现options请求
上面有文章说过http的options. 查了很久.试了很多版本的jQuery,下面这段代码在同事的机子上测试是没有问题的.正常 的请求, 一在我机子上面就会出现option,网上说先向服务器预检等. ...
- Http跨域时的Option请求
写这篇文章时,我们碰到的一个场景是:要给R系统做一个扩展小应用,前端的html.js放在R系统里,后端需要做一个单独的站点N.B.com.这就导致了跨域问题,而且要命的是,后端同学没有权限向招聘的系统 ...
- JSONP跨域的script标签请求为什么不受同源策略的限制?
在复习跨域的时候,复习到了JSONP跨域,大家都知道JSONP跨域是通过动态创建script标签,然后通过其src属性进行跨域请求的,前端需要一个数据处理的回调函数,而服务端需要配合执行回调函数,放入 ...
- 跨域GET、POST请求
跨域GET.POST请求的小结 重点:跨域POST大量数据: JQuery:$.ajax/$.getJSON支持jsonp格式的跨域,但是只支持GET方式,暂不支持POST: CORS:w3c关于跨域 ...
- Ajax跨域(CROS)请求中的Preflighted requests
Ajax跨域(CROS)请求中的Preflighted requests:https://www.aliyun.com/jiaocheng/862989.html 10 分钟理解跨域请求:https: ...
- 跨域时发送预检请求,tp5的restful无options方法的解决方案
解决 跨域问题解决 问题:使用vue-resource发送delete请求时报options请求404 思考:明明发送的是delete请求,为何变成了options请求? 答:跨域情况下,PUT,DE ...
- 彻底解决Asp.netCore WebApi 3.1 跨域时的预检查204 options重复请求的问题
Asp.netCore WebApi 3.1 跨域的预检查options问题 1:我们直接使用core跨域的中间件 ,注入跨域服务, services.AddCors(options => { ...
- ajax跨域POST时执行OPTIONS请求服务端返回403forbidden的解决方法
ajax访问服务端restful api时,由于contentType类型的原因,浏览器会先发送OPTIONS请求. 本人服务端用的是spring mvc框架,web服务器用的是tomcat的,以下给 ...
随机推荐
- Xdebug原理
前言: 前面一篇博文记录了Xdebug的安装配置.配置使用起来相对简单易懂,那么Xdebug的实现原理又是如何呢?所以就找了些资料来理解下其中的原理. 内容: Xdebug工作原理 1,IDE(如Ph ...
- Parameter not found的出现的原因
with dataM.Q_xfgl_dhjf do begin close; sql.Clear; sql.Add('insert into jfdh(jfdh_id, ...
- MongoDB入门 和nodejs操作
简介 MongoDB 开源,高性能的NoSQL数据库:支持索引.集群.复制和故障转移.各种语言的驱动程序:高伸缩性: NoSQL毕竟还处于发展阶段,也有说它的各种问题的:http://coolshel ...
- MyBatis传入多个参数的问题(转)
一.单个参数: public List<XXBean> getXXBeanList(String xxCode); <select id="getXXXBeanList&q ...
- 怎么判断pagecontrol下的TabSheet是否打开还是关闭求答案
if pagecontrol.activepage=TabSheet1 then是在当前显示页------解决方案------------------------------------------- ...
- Asp.Net Mvc的几个小问题
突然想到一些小问题,对写代码影响不大,当是又很实用. MVC 中视图中的model的大小写问题,什么时候用大写,什么时候用小写? 所谓强类型视图,就是通过@model指令指明当前Model(属性)的具 ...
- fgt2eth Script
fgt2eth Script explanation_on_how_to_packet_capture_for_only_certain_TCP_flags_v2.txt Packet capture ...
- bzoj3920: Yuuna的礼物(莫队+分块套分块)
思路挺简单的,但是总感觉好难写...码力还是差劲,最后写出来也挺丑的 这题显然是个莫队题,考虑怎么转移和询问... 根据莫队修改多查询少的特点,一般用修改快查询慢的分块来维护.查第$k_1$小的出现次 ...
- linux c 编程 ------ 串口编程
http://blog.csdn.net/specialshoot/article/details/50707965 对于串口的打开操作,必须使用O_NOCTTY参数.O_NOCTTY如果路径名指向终 ...
- Access时间日期函数大全
这里特别推荐WeekdayName() 函数.MonthName() 函数,将日期转换为中文星期名与月份,如"星期一"."五月"一.Date() 函数.Now( ...