项目里的接口都是用springmvc写的,其中在@requestmapping接口中定义了consumes="application/json",也就是该接口只接受ContentType为application/json的请求。

接口写好用工具测试接口都是可以正常请求,但是在浏览器中用ajax请求就不行。

百度一下,原来在使用Ajax跨域请求时,如果设置Header的ContentType为application/json,会分两次发送请求。第一次先发送Method为OPTIONS的请求到服务器,这个请求会询问服务器支持哪些请求方法(GET,POST等),支持哪些请求头等等服务器的支持情况。等到这个请求返回后,如果原来我们准备发送的请求符合服务器的规则,那么才会继续发送第二个请求,否则会在Console中报错。

为什么在跨域的时候设置ContentType为application/json时会请求两次?其实JQuery的文档对此有做说明。

contentType (default: 'application/x-www-form-urlencoded; charset=UTF-8')

Type: Boolean or String

When sending data to the server, use this content type. Default is "application/x-www-form-urlencoded; charset=UTF-8", which is fine for most cases. If you explicitly pass in a content-type to $.ajax(), then it is always sent to the server (even if no data is sent). As of jQuery 1.6 you can pass false to tell jQuery to not set any content type header. Note: The W3C XMLHttpRequest specification dictates that the charset is always UTF-8; specifying another charset will not force the browser to change the encoding. Note: For cross-domain requests, setting the content type to anything other than application/x-www-form-urlencoded, multipart/form-data, or text/plain will trigger the browser to send a preflight OPTIONS request to the server.

注意Note后面的描述,在跨域的时候,除了contentType为application/x-www-form-urlencoded,multipart/form-data或者text/plain外,都会触发浏览器先发送方法为OPTIONS的请求。

比如说,你原来的请求是方法方法POST,如果第一个请求返回的结果Header中的Allow属性并没有POST方法,那么第二个请求是不会发送的,此时浏览器控制台会报错,告诉你POST方法并不被服务器支持。

图中箭头指向的Allow就是服务器返回的支持的方法。

不仅如此,如果想要用ContentType:application/json发送跨域请求,服务器端还必须设置一个名为Access-Control-Allow-Headers的Header,将它的值设置为 Content-Type,表明服务器能够接收到前端发送的请求中的ContentType属性并使用它的值。否则第二次请求也是发不出去的,浏览器console会报错,并提示你服务器没有设置Access-Control-Allow-Headers。

对应到我java程序的filter过滤器里是这样

 public class MyFilter implements Filter {

     @Override
public void destroy() {
//System.out.println("过滤器销毁");
} @Override
public void doFilter(ServletRequest request, ServletResponse response,
HttpServletRequest httpRequest = (HttpServletRequest) request;
String type=httpRequest.getMethod(); if (type.toUpperCase().equals("OPTIONS")==true) {
httpResponse.setHeader("Access-Control-Allow-Headers", "content-type, accept");
15 httpResponse.setHeader("Access-Control-Allow-Methods", "POST");
16 httpResponse.setStatus(200);
17 httpResponse.setContentType("text/plain;charset=utf-8");
18 httpResponse.setCharacterEncoding("utf-8");
responseContentByte="{\"test\":\"OPTIONS\"}".getBytes();
}
} @Override
public void init(FilterConfig arg0) throws ServletException {
//System.out.println("过滤器初始化");
} }

Ajax跨域之ContentType为application/json请求失败的问题的更多相关文章

  1. Ajax 跨域,这应该是最全的解决方案了

    https://segmentfault.com/a/1190000012469713 前言 从刚接触前端开发起,跨域这个词就一直以很高的频率在身边重复出现,一直到现在,已经调试过N个跨域相关的问题了 ...

  2. ajax跨域,这应该是最全的解决方案了

    前言 从刚接触前端开发起,跨域这个词就一直以很高的频率在身边重复出现,一直到现在,已经调试过N个跨域相关的问题了,16年时也整理过一篇相关文章,但是感觉还是差了点什么,于是现在重新梳理了一下. 个人见 ...

  3. ajax 跨域----好用的解决方案

    一.前言 跨域这个词就一直以很高的频率在身边重复出现,一直到现在,已经调试过N个跨域相关的问题了! 但是感觉还是差了点什么,于是现在重新梳理了一下.个人见识有限,如有差错,请多多见谅 二.前言 关于跨 ...

  4. ajax跨域 (转)

    题纲 关于跨域,有N种类型,本文只专注于ajax请求跨域(,ajax跨域只是属于浏览器”同源策略”中的一部分,其它的还有Cookie跨域iframe跨域,LocalStorage跨域等这里不做介绍), ...

  5. Ajax跨域解决方案大全

    题纲 关于跨域,有N种类型,本文只专注于ajax请求跨域(,ajax跨域只是属于浏览器"同源策略"中的一部分,其它的还有Cookie跨域iframe跨域,LocalStorage跨 ...

  6. 一篇关于ajax跨域问题的解决方案

    这几天没事,我有一个好友,让我帮他做一个机器人对话demo, 我说 看看有没有时间(其实自己一脸懵逼) 然后百度了一下,发现了一个机器人  -(连接就不弄出来了,可以私底下交流) ,,我是用这个的 好 ...

  7. Ajaxadr ajax跨域请求crossdomain

    最近工作需要用到ajax跨域请求参数,网上找很很久,最终得到解决之道.分享一下吧,希望能帮到各位 也许你已经发现在浏览器直接敲路径能获得对方提供接口的参数,而一到项目中Ajax请求却老是失败.原因是, ...

  8. JQuery.Ajax + 跨域 (crossDomain) + POST + JSON + WCF RESTful, 5大陷阱和解决方案

    JQuery.Ajax + 跨域 (crossDomain) + POST + JSON + WCF RESTful, 5大陷阱和解决方案 最近在开发WSS RESTful服务的时候, 碰到了这些个纠 ...

  9. 说说JSON和JSONP,浅析JSONP解决AJAX跨域问题

    说到AJAX就会不可避免的面临两个问题,第一个是AJAX以何种格式来交换数据?第二个是跨域的需求如何解决?这两个问题目前都有不同的解决方案,比如数据可以用自定义字符串或者用XML来描述,跨域可以通过服 ...

随机推荐

  1. Material Design之NavigationView和DrawerLayout实现侧滑菜单栏

    本文将介绍使用Google最新推出规范式设计中的NavigationView和DrawerLayout结合实现侧滑菜单栏效果,NavigationView是android-support-design ...

  2. hive基本的操作语句(实例简单易懂,create table XX as select XX)

    hive建表语句DML:https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-Cr ...

  3. 【一天一道LeetCode】#13. Roman to Integer

    一天一道LeetCode系列 (一)题目 Given a roman numeral, convert it to an integer. Input is guaranteed to be with ...

  4. This version of the rendering library is more recent than your version of ADT plug-in. Please update

    预览layout.xml文件时提示: This version of the rendering library is more recent than your version of ADT plu ...

  5. C++项目中的extern "C" {}(转)

    注:本文转自吴秦先生的博客http://www.cnblogs.com/skynet/archive/2010/07/10/1774964.html#.吴秦先生的博客写的非常详细深刻容易理解,故特转载 ...

  6. android 实现倒影

    首先,文章中出现的Gallery 已经不再适用,替代方法请看我的另一篇文章http://blog.csdn.net/xiangzhihong8/article/details/51120460 不过对 ...

  7. 地产IT人福利:帆软地产BI解决方案全解析

    解决方案下载地址 帆软大型地产集团项目解决方案 下载地址:http://pan.baidu.com/s/1pJGeqKF帆软地产BI解决方案之KPI考核系统 下载地址:http://pan.baidu ...

  8. javascript中如何让类工厂和构造函数变成同一个函数

    我们知道在js中可以用一个函数来定义对象的类,该函数称之为对象的构造函数,我们在需要create对象的时候直接调用这个构造函数即可: var Man = funciton(name){ this.na ...

  9. 开发composer包,打通github和packagist,并自动更新

    1. 首先需要本地安装好composer,并配置好环境变量,在命令行输入composer,显示以下信息就表示正常安装 2. 在github对应项目的根目录下进行初始化composer 初始化完成后,就 ...

  10. Linux的pwd命令详解

    在Linux层次结构中,用户可以在被授权的任意目录下利用mkdir命令创建新目录,也可以利用cd命令从一个目录转换到另一个目录.然而,没有提示符来告知用户目前处于哪一个目录中.想要知道当前所处的目录, ...