记录我开发工作中遇到HTTP跨域和OPTION请求的一个坑
我通过这篇文章把今天工作中遇到的HTTP跨域和OPTION请求的一个坑记录下来。
场景是我需要在部署在域名a的Web应用里用JavaScript去消费一个部署在域名b的服务器上的服务。域名b上的服务也是我开发的,因此我将域名a加到了该服务的HTTP响应结构的头文件里,这样就允许了域名a上的JavaScript代码用AJAX访问域名b的服务。
域名b上的服务是一个Servlet,允许域名a跨域访问的代码就一行:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 做业务逻辑
response.setHeader("Access-Control-Allow-Origin", "域名a");
}
我在域名a的Web应用里用AJAX发起服务请求:
执行后,发现并没有显示200的弹出窗口。
错误消息:Request header field Authorization is not allowed by Access-Control-Allow-Headers in preflight response.
观察Chrome开发者工具,发现其实域名b的服务已经成功执行了,确实返回了200的Status code,
而且我已经从Chrome开发者工具里观察到浏览器已经成功接到域名b发送回来的请求了。
那这个错误是什么鬼呢?根据错误消息“Request header field Authorization is not allowed by Access-Control-Allow-Headers in preflight response” Google了一下,发现一些朋友遇到同样的问题:
1. 如何解决出现AXIOS的Request header field Content-Type is not allowed by Access-Control-Allow-Headers in preflight response.
网页地址: https://www.cnblogs.com/caimuqing/p/6733405.html
这位朋友的解决方案:
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "*");
response.setHeader("Access-Control-Allow-Headers", "Content-Type,Access-Token");
response.setHeader("Access-Control-Expose-Headers", "*");
if (request.getMethod().equals("OPTIONS")) {
HttpUtil.setResponse(response, HttpStatus.OK.value(), null);
return;
}
但我试过,在我的场景下还是不工作,因为我的例子里,服务器已经针对OPTIONS请求返回HTTP 200的状态码了。
2. 这个Stackoverflow的帖子里,很多朋友都提供了自己的解决方案。
我一一试过,在我的场景里都不能工作。
于是我查询了Mozilla的一篇文档:HTTP访问控制(CORS)
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS
里面谈到了,在某些情况下,浏览器在发起“需要预检的请求”之前,必须首先发起一个“预检请求(Preflight)”到服务器,以探测服务器是否允许这个实际请求。"预检请求"机制的使用,是为了避免跨域请求对服务器的用户数据产生未预期的影响。
那么哪些请求算作“需要预检的请求”呢?Mozilla的这篇文档定义得很清楚:
当请求满足下述任一条件时,即应首先发送预检请求:
- 使用了下面任一 HTTP 方法:
- PUT
- DELETE
- CONNECT
- OPTIONS
- TRACE
- PATCH
- 人为设置了对 CORS 安全的首部字段集合之外的其他首部字段。该集合为:
- Accept
- Accept-Language
- Content-Language
- Content-Type (but note the additional requirements below)
- DPR
- Downlink
- Save-Data
- Viewport-Width
- Width
- Content-Type 的值不属于下列之一:
- application/x-www-form-urlencoded
- multipart/form-data
- text/plain
我再检查我的代码,因为我在HTTP请求里用xhr.setRequestHeader("Authorization", "用户名:密码的base64编码" )添加了用于Basic Authentication的头部,因此迫使该请求成为了“需要预检的请求”,所以才有了OPTION请求的发送。
现在我将其注释掉:
这次遇到了401 Unauthorized错误了:
然而没有预检请求OPTION发出来了,请求类型变成了我期望的POST方式了。
但是现在就陷入了一个矛盾的境地:如果在请求头部加上Basic Authentication的信息,会遇到错误消息“Request header field Authorization is not allowed by Access-Control-Allow-Headers in preflight response.”。如果去掉,虽然避免了预检请求,但是又遇到401 Unauthorized错误了。
于是,我换了一种认证方式,终于成功实现了期望的跨域请求,在我域名a的前端应用里打印出了来自于域名b的服务的响应。
我使用了form认证方式,这种方式不会造成该请求成为一个”需要预检的请求“,所以最后跨域成功了。
var formData = new FormData();
formData.append('sap-client', "001");
formData.append('sap-user', "用户名");
formData.append('sap-password', "用户密码");
var request = new XMLHttpRequest();
request.open("POST", "域名b的url",false);
request.send(formData);
alert("response: " + request.responseText);
希望我的这个踩坑经历对大家有点帮助。
要获取更多Jerry的原创技术文章,请关注公众号"汪子熙"或者扫描下面二维码:


记录我开发工作中遇到HTTP跨域和OPTION请求的一个坑的更多相关文章
- 跨域资源共享/option 请求产生原因
https://blog.csdn.net/hfahe/article/details/7730944
- js--前端开发工作中常见的时间处理问题
前言 在前端开发工作中,服务端返回的时间数据或者你传递给服务端的时间参数经常会遇到时间格式转换及处理问题.这里分享一些我收集到的一些处理方法,方便日后工作中快速找到.先附上必须了解的知识内置对象传送门 ...
- 前后端分离 开发环境通过CORS实现跨域联调
通过JSONP实现跨域已是老生常谈,JSONP跨域限制多,最近了解了一下CORS. 参考: https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Acce ...
- HTML5中Access-Control-Allow-Origin解决跨域问题
www.111cn.net 更新:2015-01-07 编辑:flyfox 来源:转载 跨域在开发中一些是一个比较常见的问题虽然有json或者xml来解决,现在html5开始流行了,我们可以通过Acc ...
- django中的缓存 跨域问题(同源策略)
django缓存机制 在动态网站中,用户所有的请求,服务器都会去数据库中进行相应的增,删,查,改,渲染模板,执行业务逻辑,最后生成用户看到的页面. 当一个网站的用户访问量很大的时候,每一次的的后台操作 ...
- 如何在ASP.NET Core中实现CORS跨域
注:下载本文的完整代码示例请访问 > How to enable CORS(Cross-origin resource sharing) in ASP.NET Core 如何在ASP.NET C ...
- 在ASP.NET MVC3 中利用Jsonp跨域访问
在ASP.NET MVC3 中利用Jsonp跨域访问 在信息系统开发的时,根据相关业务逻辑难免会多系统之间互相登录.一般情况下我们需要在多系统之间使用多个用户名和密码.这样客户就需要在多个系统之间重复 ...
- vue-cli项目开发/生产环境代理实现跨域请求+webpack配置开发/生产环境的接口地址
一.开发环境中跨域 使用 Vue-cli 创建的项目,开发地址是 localhost:8080,需要访问非本机上的接口http://10.1.0.34:8000/queryRole.不同域名之间的访问 ...
- Android中WebView的跨域漏洞分析和应用被克隆问题情景还原(免Root获取应用沙盒数据)
一.前言 去年年底支付宝的被克隆漏洞被爆出,无独有偶就是腾讯干的,其实真正了解这个事件之后会发现,感觉是针对支付宝.因为这个漏洞找出肯定花费了很大劲,主要是因为支付宝的特殊业务需要开启了WebView ...
随机推荐
- Eclipse中导入Hadoop源代码工程
以hadoop 2.7.3为例, jdk1.7.0_80 , Eclipse Mars(4.5), Apache Maven 3.0.5 mvn时需要使用root权限,即县切换到root用户,用命 ...
- J - 吉哥系列故事――恨7不成妻
#include "cstdio" #include "math.h" #include "cstring" #define mod 100 ...
- iOS开发 - 多线程实现方案之NSThread篇
NSThread API //类方法:创建一个线程 + (void)detachNewThreadWithBlock:(void (^)(void))block API_AVAILABLE(macos ...
- 采集-telegraf
1 介绍 Telegraf是一款Go语言编写的metrics收集.处理.聚合的代理其设计目标是较小的内存使用,通过插件来构建各种服务和第三方组件的metrics收集Telegraf由4个独立的插件驱动 ...
- with rollup
实验吧的一道ctf题,这两天无聊,做做ctf题.在实验吧被一道也题卡了好久. 页面很简单就是一个登陆页面,按照之前的经验觉得应该是注入吧.再看题猜测应该是绕waf之类的. 查看页面源码找到了提供的源代 ...
- CF ECR59div2 D
题目本质:如果答案是i,那么从行和列两维都会满足:以i的倍数分块,矩阵值相同. 一种解决方法: 1.首先题目里说了要在n的约数里找orzorz…… 2.块中需要一整排都相同.用“与前一排相同否?”来判 ...
- struts2的@Result annotation 如何添加params,并且在页面取值
http://www.bubuko.com/infodetail-2492575.html .............................................. 标签:lai ...
- python入门之生成器
生成器 通过列表生成式,可以直接创建一个列表,但是,受到内存限制,列表容量肯定是有限得.而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果仅仅需要访问前面几个元素,那后面绝大多数元素 ...
- python学习之结构语句
一 循环语句: 1.1 for x in rang(n) :#rang(n)生成左闭右开区间的序列 1.2 while x 条件n: 二条件语句: if 条件表达式: elif 表达式: elif 表 ...
- vue echarts 大小自适应
窗口大小时候 ,echarts图自适应 在创建图表的方法中直接,用resize方法 let myChart=this.$refs.myChart; let mainChart = echarts.in ...