解决AJAX跨域:1、利用JSONP;2、JS设置Header
一、利用JSONP:
首先来看看在页面中如何使用jQuery的ajax解决跨域问题的简单版:
$(document).ready(function(){
var url='http://localhost:8080/WorkGroupManagment/open/getGroupById"
+"?id=1&callback=?';
$.ajax({
url:url,
dataType:'jsonp',
processData: false,
type:'get',
success:function(data){
alert(data.name);
},
error:function(XMLHttpRequest, textStatus, errorThrown) {
alert(XMLHttpRequest.status);
alert(XMLHttpRequest.readyState);
alert(textStatus);
}
});
});
这样写是完全没有问题的,起先error的处理函数中仅仅是alert(“error”),为了进一步弄清楚是什么原因造成了错误,故将处理函数变为上面的实现方式。最后一行alert反馈parsererror问题。百思不得其解,原因是jsonp的格式与json格式有着细微的差别,所以在server端的代码上稍稍有所不同。
比较一下json与jsonp格式的区别:
JSON格式:
{
"message":"获取成功",
"state":"",
"result":{"name":"工作组1","id":,"description":""}
}
JSONP格式:
callback({
"message":"获取成功",
"state":"",
"result":{"name":"工作组1","id":,"description":""}
})
看出来区别了吧,在url中callback传到后台的参数是什么callback就是什么,jsonp比json外面有多了一层callback()。这样就知道怎么处理它了,于是修改后台代码。
后台java代码最终如下:
@RequestMapping(value = "/getGroupById")
public String getGroupById(@RequestParam("id") Long id, HttpServletRequest request, HttpServletResponse response) throws IOException {
String callback = request.getParameter("callback");
ReturnObject result = null;
Group group = null;
try {
group = groupService.getGroupById(id);
result = new ReturnObject(group, "获取成功", Constants.RESULT_SUCCESS);
} catch (BusinessException e) {
e.printStackTrace();
result = new ReturnObject(group, "获取失败", Constants.RESULT_FAILED);
}
String json = JsonConverter.bean2Json(result);
response.setContentType("text/html");
response.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
out.print(callback + "(" + json + ")");
return null;
}
注意:这里需要先将查询结果转换为json格式,然后用参数callback在json外面再套一层,就变成了jsonp。指定数据类型为jsonp的ajax就可以做进一步处理了。
虽然这样解决了跨域问题,还是回顾下造成parsererror的原因。原因在于盲目的把json格式的数据当做jsonp格式的数据让ajax处理,造成了这个错误,此时server端代码是这样的:
@RequestMapping(value = "/getGroupById")
@ResponseBody
public ReturnObject getGroupById(@RequestParam("id") Long id,HttpServletRequest request, HttpServletResponse response){
String callback = request.getParameter("callback");
ReturnObject result = null;
Group group = null;
try{
group = groupService.getGroupById(id);
result = new ReturnObject(group, "获取成功", Constants.RESULT_SUCCESS);
} catch (BusinessException e) {
e.printStackTrace();
result = new ReturnObject(group, "获取失败", Constants.RESULT_FAILED);
}
return result;
}
//错误处理方式
二、JS设置Header,实现跨域访问:
受浏览器的同源策略限制,JavaSript只能请求本域内的资源。跨域资源共享(Cross-Origin Resource Sharing, CORS)是为解决Ajax技术难实现跨域问题而提出的一个规范,这个规范试着从根本上解决安全的跨域资源共享问题。在此之前,解决此类问题的途径往往是服务器代理、JSONP等,治标不治本。目前基本所有浏览器都已经支持该规范。
一个域是由schema、host、port三者共同组成,与路径无关。所谓跨域,是指在http://example-foo.com/域上通过XMLHttpRequest对象调用http://example-bar.com/域上的资源。CORS约定服务器端和浏览器在HTTP协议之上,通过一些额外HTTP头部信息,进行跨域资源共享的协商。服务器端和浏览器都必需遵循规范中的要求。
CORS把HTTP请求分成两类,不同类别按不同的策略进行跨域资源共享协商。
1. 简单跨域请求。
当HTTP请求出现以下两种情况时,浏览器认为是简单跨域请求:
1). 请求方法是GET、HEAD或者POST,并且当请求方法是POST时,Content-Type必须是application/x-www-form-urlencoded, multipart/form-data或着text/plain中的一个值。
2). 请求中没有自定义HTTP头部。
对于简单跨域请求,浏览器要做的就是在HTTP请求中添加Origin Header,将JavaScript脚本所在域填充进去,向其他域的服务器请求资源。服务器端收到一个简单跨域请求后,根据资源权限配置,在响应头中添加Access-Control-Allow-Origin
Header。浏览器收到响应后,查看Access-Control-Allow-Origin Header,如果当前域已经得到授权,则将结果返回给JavaScript,否则浏览器忽略此次响应。
2. 带预检(Preflighted)的跨域请求。
当HTTP请求出现以下两种情况时,浏览器认为是带预检(Preflighted)的跨域请求:
1). 除GET、HEAD和POST(only with application/x-www-form-urlencoded, multipart/form-data, text/plain Content-Type)以外的其他HTTP方法。
2). 请求中出现自定义HTTP头部。
带预检(Preflighted)的跨域请求需要浏览器在发送真实HTTP请求之前先发送一个OPTIONS的预检请求,检测服务器端是否支持真实请求进行跨域资源访问,真实请求的信息在OPTIONS请求中通过Access-Control-Request-Method
Header和Access-Control-Request-Headers
Header描述,此外与简单跨域请求一样,浏览器也会添加Origin
Header。服务器端接到预检请求后,根据资源权限配置,在响应头中放入Access-Control-Allow-Origin
Header、Access-Control-Allow-Methods和Access-Control-Allow-Headers
Header,分别表示允许跨域资源请求的域、请求方法和请求头。此外,服务器端还可以加入Access-Control-Max-Age
Header,允许浏览器在指定时间内,无需再发送预检请求进行协商,直接用本次协商结果即可。浏览器根据OPTIONS请求返回的结果来决定是否继续发送真实的请求进行跨域资源访问。这个过程对真实请求的调用者来说是透明的。
XMLHttpRequest支持通过withCredentials属性实现在跨域请求携带身份信息(Credential,例如Cookie或者HTTP认证信息)。浏览器将携带Cookie
Header的请求发送到服务器端后,如果服务器没有响应Access-Control-Allow-Credentials
Header,那么浏览器会忽略掉这次响应。
这里讨论的HTTP请求是指由Ajax XMLHttpRequest对象发起的,所有的CORS HTTP请求头都可由浏览器填充,无需在XMLHttpRequest对象中设置。以下是CORS协议规定的HTTP头,用来进行浏览器发起跨域资源请求时进行协商:
1. Origin。HTTP请求头,任何涉及CORS的请求都必需携带。
2. Access-Control-Request-Method。HTTP请求头,在带预检(Preflighted)的跨域请求中用来表示真实请求的方法。
3. Access-Control-Request-Headers。HTTP请求头,在带预检(Preflighted)的跨域请求中用来表示真实请求的自定义Header列表。
4.
Access-Control-Allow-Origin。HTTP响应头,指定服务器端允许进行跨域资源访问的来源域。可以用通配符*表示允许任何域的JavaScript访问资源,但是在响应一个携带身份信息(Credential)的HTTP请求时,Access-Control-Allow-Origin必需指定具体的域,不能用通配符。
5. Access-Control-Allow-Methods。HTTP响应头,指定服务器允许进行跨域资源访问的请求方法列表,一般用在响应预检请求上。
6. Access-Control-Allow-Headers。HTTP响应头,指定服务器允许进行跨域资源访问的请求头列表,一般用在响应预检请求上。
7. Access-Control-Max-Age。HTTP响应头,用在响应预检请求上,表示本次预检响应的有效时间。在此时间内,浏览器都可以根据此次协商结果决定是否有必要直接发送真实请求,而无需再次发送预检请求。
8. Access-Control-Allow-Credentials。HTTP响应头,凡是浏览器请求中携带了身份信息,而响应头中没有返回Access-Control-Allow-Credentials: true的,浏览器都会忽略此次响应。
总结:只要是带自定义header的跨域请求,在发送真实请求前都会先发送OPTIONS请求,浏览器根据OPTIONS请求返回的结果来决定是否继续发送真实的请求进行跨域资源访问。所以复杂请求肯定会两次请求服务端。
js 端的ajax请求:
$.ajax({
url: "http://test.com",
dataType: 'json',
type: 'GET',
beforeSend: function (xhr) {
xhr.setRequestHeader("Test", "testheadervalue");
},
async: false,
cache: false,
//contentType: 'application/x-www-form-urlencoded',
success: function (sResponse) {
}
});
服务端的action:
//允许跨域访问
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS,DELETE,PUT");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Test");
总结:
1、JSONP格式:(1)url加:&callback=?;type变为"jsonp";(2)服务器端返回数据要为jsonp格式,即:out.print(callback + "(" + json + ")");要套一层callback()
2、服务器Action层增加Header头信息
解决AJAX跨域:1、利用JSONP;2、JS设置Header的更多相关文章
- 谷歌浏览器解决ajax跨域问题
在用mui和H5+做混合开发,会利用HBuildx去真机调试,可真机调试总有问题所在,懂得人自然懂,而我们直接打开页面显示的只有一个静态的页面,是获取不到数据的在这里我想说的不是代码中利用jsonp, ...
- e3mall商城总结11之sso系统的分析、应用以及解决ajax跨域问题
说在前面的话 一.sso系统分析 什么是sso系统 SSO英文全称Single Sign On,单点登录.SSO是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统.它包括可以将这次 ...
- 如何解决ajax跨域问题(转)
由 于此前很少写前端的代码(哈哈,不合格的程序员啊),最近项目中用到json作为系统间交互的手段,自然就伴随着众多ajax请求,随之而来的就是要解决 ajax的跨域问题.本篇将讲述一个小白从遇到跨域不 ...
- 看小白如何解决ajax跨域问题
由于此前很少写前端的代码(哈哈,不合格的程序员啊),最近项目中用到json作为系统间交互的手段,自然就伴随着众多ajax请求,随之而来的就是要解决ajax的跨域问题.本篇将讲述一个小白从遇到跨域不知道 ...
- 如何解决ajax跨域问题
如何解决ajax跨域问题(转) 由 于此前很少写前端的代码(哈哈,不合格的程序员啊),最近项目中用到json作为系统间交互的手段,自然就伴随着众多ajax请求,随之而来的就是要解决 ajax的跨域问题 ...
- 如何解决Ajax跨域问题-1
如何解决Ajax跨域问题 最近在做AJAX调用C的问题,出现跨域问题,学习总结如下: 在做ajax读取数据的时候,经常会遇到ajax需要跨域的问题,但由于浏览器安全方面的限制,XMLHttpReque ...
- 【PHP】Ajax跨域解决方案 、jsonp、cors
参考文章: 1.https://blog.csdn.net/u014727260/article/details/72793459 (后台java,实际上差不多) 2. 如何解决ajax跨域传输 数据 ...
- JAVAEE——宜立方商城11:sso登录注册功能实现、通过token获得用户信息、Ajax跨域请求(jsonp)
1. 学习计划 第十一天: 1.sso注册功能实现 2.sso登录功能实现 3.通过token获得用户信息 4.Ajax跨域请求(jsonp) 2. Sso系统工程搭建 需要创建一个sso服务工程,可 ...
- 【前端_js】解决ajax跨域请求数据
1.ajax发送请求必须遵循同源策略,即请求方和相应方的协议头.域名.端口全部一样.只要三者有一个不一样都视为跨域,浏览器出于安全考虑不允许跨域访问. 解决ajax跨域访问的常用方法: a.使用jso ...
- 如何解决ajax跨域请求?
1.什么是跨域? a.域名不同 b.域名相同,端口不同 注:只有域名相同,端口相同时,才可以访问数据 可以使用jsonp解决ajax跨域请求的问题. 2.什么是jsonp? Jsonp其实就是一个跨域 ...
随机推荐
- 我XXXX!!!够了!!!从github拉到dockerhub,再用daocloud加速下载
史上比较曲折的救国方式了... 先在git hub上申请帐号,导入dockerfile. 然后在docker hub上关联git hub帐号作自动构建. 再用daocloud作加速,将docker i ...
- 根据C# 事件思想来实现 php 事件
事件定义 当我们使用委托场景时,我们很希望有这样两个角色出现:广播者和订阅者.我们需要这两个角色来实现订阅和广播这种很常见的场景. 广播者这个角色应该有这样的功能:包括一个委托字段,通过调用委托来发出 ...
- JS中的对象和方法简单剖析
众所周知,在js中对象就是精髓,不理解对象就是不理解js. 那么什么事js中的对象呢? 在js中,几乎一切皆对象: Boolean ,String,Number可以是对象(或者说原生数据被认作对象): ...
- mybatis 报错: Invalid bound statement (not found)
错误: org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): test.dao.Produc ...
- 【ASP.NET MVC】 路由机制:命名路由
首先看一下命名路由和没有命名的差别: 命名路由: routes.MapRoute( name: "Test", // Route name url: "code/p/{a ...
- 234. Palindrome Linked List【Easy】【判断链表是否回文】
Given a singly linked list, determine if it is a palindrome. Example 1: Input: 1->2 Output: false ...
- 1、编译安装Nginx
1.1 如何选择web服务器 在实际工作中,我们需要根据业务需求来选择合适的业务服务软件,有关web服务,选择建议如下: 静态业务:若是高并发场景,尽量采用nginx或lighttpd,二者首选ngi ...
- CUPOJ6242: LHC的二进制升级版
6242: LHC的二进制升级版 时间限制:1秒 内存限制:128MB Special Judge 提交:6 正确:3 题目描述 在发现了3的二进制特殊性质后,LHC认为形如1.3.7.15..... ...
- Java 线程池的实现
http://blog.csdn.net/iterzebra/article/details/6758481 http://blog.sina.com.cn/s/blog_4914a33b010118 ...
- JDK源码学习笔记——TreeMap及红黑树
找了几个分析比较到位的,不再重复写了…… Java 集合系列12之 TreeMap详细介绍(源码解析)和使用示例 [Java集合源码剖析]TreeMap源码剖析 java源码分析之TreeMap基础篇 ...