记录我开发工作中遇到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的帖子里,很多朋友都提供了自己的解决方案。

https://stackoverflow.com/questions/42061727/cors-error-request-header-field-authorization-is-not-allowed-by-access-control/42061962

我一一试过,在我的场景里都不能工作。

于是我查询了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的原创技术文章,请关注公众号"汪子熙"或者扫描下面二维码:

原文地址:https://www.cnblogs.com/sap-jerry/p/9818756.html

时间: 2024-10-18 12:18:33

记录我开发工作中遇到HTTP跨域和OPTION请求的一个坑的相关文章

解决前端开发环境中的的跨域问题

一.为什么会有跨越问题是客户端浏览器同源策略导致的,就是浏览器不允许不同源的站点相互访问.试想一下要是没有这个,那站点里的安全信息如cookie,账号/密码等是不是很容易被其它站点获取.二.解决思路知道是客户端浏览器为了安全使用同源策略导致的,而服务端是没有这个限制的,那我们就只能通过服务端进行跨域了.不管是jsonp,core,还是代理的方式,都是需要服务配合的.哈哈,这也是为啥后端和生产环境下比较少听说跨域的问题,所以这里介绍前端开发环境中的几种解决方法.三.解决方案1.完全交予后端解决,配

解决easyui tabs中href无法跨域跳转

<!DOCTYPE HTML> <html> <head> <meta http-equiv="content-type" content="text/html" /> <meta name="author" content="blog.anchen8.net" /> <script type="text/javascript" src=&q

jquery中ajax处理跨域的三大方式

一.处理跨域的方式: 1.代理 2.XHR2 HTML5中提供的XMLHTTPREQUEST Level2(及XHR2)已经实现了跨域访问.但ie10以下不支持 只需要在服务端填上响应头: ? 1 2 3 header("Access-Control-Allow-Origin:*"); /*星号表示所有的域都可以接受,*/ header("Access-Control-Allow-Methods:GET,POST"); 3.jsonP 原理: ajax本身是不可以跨

妥善的ajax跨域提交post请求的解决方案,结合PHP与jquery

开发背景: 在开发中采用了一个新的架构,将大部分客户的留言功能集成到一个公共API提交保存,采用不同的用户名区分,供客户查询自己网站的留言,这样节约了客户网站的资源,也提升了维护性. 那么在提交时不能采用直接的post提交,否则会产生跳转,使访客混乱,所以采用ajax提交留言内容至公共服务器:http://wx.igooda.cn/index.php/messagesave,但尝试后发现不能提交post请求,百度后查询结果是跨域只能是get请求,这对留言内容多的来说,是不可行的.还有一种解决方案

跨域发送HTTP请求详解

------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 本篇博客讲述几种跨域发HTTP请求的几种方法,POST请求,GET请求 目录: 一,采用JsonP的方式(只能是GET) 二,采用CROS的方式(需要在接收的一端也有配置) 三,采用form表单的方式(有些时候会存在问题,一会详细说明) 四,采用代理网站帮忙转(不推荐,不安全,性能低,不做解释) 五,后台JAVA后端通过net方式发送 一,jsonP的方式: $.ajax({ url: "http://lo

中止请求和超时 跨域的HTTP请求 认证方式 JSONP

中止请求和超时 一个栗子在上传多少秒以后直接终止请求 // 发起HTTP GEt请求获取指定URl的内容 // 如果响应成功到达,将会传入responseText给回调函数 // 如果响应在timeout毫秒内没有到达,将会中止这个请求 function timedGetText(url, timeout, callback) { var request = new XMLHttpRequest(); // 创建新请求 var timedout = false; // 是否超时,设置标志 //

J2EE开发工作中遇到的异常问题及解决方法总结

转自:http://blog.csdn.net/rchm8519/article/details/41624381 1.    HttpClient I/O exception: 错误信息:I/O exceptioncaught when processing request: Connection timed out:connect 错误原因:IP不正确. 解决方法:改正IP 2.    Ambiguous handler methods mapped 错误信息:java.lang.Illeg

前端开发环境搭建以及如何跨域

前端本地开发环境搭建总结: 安装nodejs环境(推荐6.0以后的LTS版本),安装完之后打开终端(mac平台),windows平台可以 WIN+R 打开运行,输入cmd,打开命令窗口,输入npm --version,如果能看到版本,说明已经安装成功: 在本地电脑的工作目录下面,执行 "git clone" + gitlab仓库的地址,把项目克隆下来: 使用编辑器(推荐webstorm或者vs code,功能强大,当然如果有其他熟悉的IDE也可以,前提是熟悉)打开项目,找到node的s

PhoneGap开发跨平台移动APP - 解决跨域资源共享

解决跨域资源共享 一.WebApi解决跨域资源共享. 开发中选择WebApi来作为服务端的数据接口,由于使用PhoneGap,就需要通过js来获取远程远程数据服务器的数据,由于同源策略的限制,这就涉及到跨域资源共享问题. 首先新建一个简单的WebApi项目, 使用微软的CORS解决方案,再Nugget中下载microsoft.aspnet.webapi.cors. 配置WebApiConfig: //这里先用*来测试,生产环境下,这样配置是不安全的,需要做一些限制.config.EnableCo