随着软件开发分工趋于精细,前后端开发分离成为趋势,前端同事负责前端页面的展示及页面逻辑处理,服务端同事负责业务逻辑处理同时通过API为前端提供数据也为前端提供数据的持久化能力,考虑到前后端同事开发工具和习惯的不同,必然需要将前后端项目进行独立,再者考虑到网站访问速度的问题,需要将静态资源部署到CDN服务器上这样项目分离也成为了必然。然而项目分离部署分离带来的问题就是跨域请求的问题,本例对比较流行的两种跨域访问方式(Jsonp和CORS)进行讨论。

一、简要介绍

1.1、JSONP

  JSONP是利用浏览器对script的资源引用没有同源限制,通过动态插入一个script标签,当资源加载到页面后会立即执行的原理实现跨域的。JSONP是一种非正式传输协议,该协议的一个要点就是允许用户传递一个callback或者开始就定义一个回调方法,参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。
  JSONP只支持GET请求而不支持POST等其它类型的HTTP请求,它只支持跨域HTTP请求这种情况,不能解决不同域的两个页面之间如何进行JavaScript调用的问题,JSONP的优势在于支持老式浏览器,弊端也比较明显:需要客户端和服务端定制进行开发,服务端返回的数据不能是标准的Json数据,而是callback包裹的数据。

1.2、CORS

  CORS是现代浏览器支持跨域资源请求的一种方式,全称是"跨域资源共享"(Cross-origin resource sharing),当使用XMLHttpRequest发送请求时,浏览器发现该请求不符合同源策略,会给该请求加一个请求头:Origin,后台进行一系列处理,如果确定接受请求则在返回结果中加入一个响应头:Access-Control-Allow-Origin;浏览器判断该相应头中是否包含Origin的值,如果有则浏览器会处理响应,我们就可以拿到响应数据,如果不包含浏览器直接驳回,这时我们无法拿到响应数据。
  CORS与JSONP的使用目的相同,但是比JSONP更强大,CORS支持所有的浏览器请求类型,承载的请求数据量更大,开放更简洁,服务端只需要将处理后的数据直接返回,不需要再特殊处理。

二、跨域解决方案距离

2.1、JSONP方案实现跨域

前段AJAX请求

 $.ajax({
url: "http://otherdomain.com/manage/role/get",
async: false,
type: "get", dataType: "jsonp",
data:{
"id":1
},
jsonp: "callback",
jsonpCallback:"fn",
success: function(data){
alert(data.code);
},
error: function(){
alert('fail');
}
})

服务端响应数据

 @RequestMapping("/manage/role/get")
@ResponseBody
public String get(HttpServletRequest request, HttpServletResponse response) {
BaseOutput outPut = new BaseOutput();
try {
QueryFilter filter = new QueryFilter(request);
logger.info(filter.toString());
String id = filter.getParam().get(MainConst.KEY_ID);
if(!StringUtil.isEmpty(id)) {
ImRole role = roleService.getByPk(filter);
outPut.setData(role);
}
else {
outPut.setCode(OutputCodeConst.INPUT_PARAM_IS_NOT_FULL);
outPut.setMsg("The get id is needed.");
}
} catch (Exception e) {
logger.error("获取角色数据异常!", e);
outPut.setCode(OutputCodeConst.UNKNOWN_ERROR);
outPut.setMsg("获取角色数据异常! " + e.getMessage());
}
return "fn("+JsonUtil.objectToJson(outPut)+")";
}

注意内容:

1、Ajax请求需要设置请求类型为Jsonp

dataType: "jsonp"

2、Ajax请求需要设置回调函数,当前函数值必须与服务器响应包含的callback名称相同

jsonpCallback:"fn"

3、Ajax请求可以设置jsonp(可选),传递给请求处理程序或页面,用以获得jsonp回调函数名的参数名,默认为:callback

jsonp: "callback"

4、服务端返回Json数据必须使用jsonpCallback设置的值进行包裹

return "fn("+JsonUtil.objectToJson(outPut)+")"

2.2、CORS方案实现跨域

前段AJAX请求

 function test() {
$.ajax({
url: "http://localhost:8080/AdsServer/manage/role/get",
type: "get",
async: false,
data:{
"id":1
},
dataType:"json",
withCredentials:true,
success: function(data){
alert(data);
alert(data.code);
},
error: function(){
alert('fail');
}
})
}

服务端响应数据

 @RequestMapping("/manage/role/get")
@ResponseBody
public String get(HttpServletRequest request, HttpServletResponse response) {
BaseOutput outPut = new BaseOutput();
try {
QueryFilter filter = new QueryFilter(request);
logger.info(filter.toString());
String id = filter.getParam().get(MainConst.KEY_ID);
if(!StringUtil.isEmpty(id)) {
ImRole role = roleService.getByPk(filter);
outPut.setData(role);
}
else {
outPut.setCode(OutputCodeConst.INPUT_PARAM_IS_NOT_FULL);
outPut.setMsg("The get id is needed.");
}
} catch (Exception e) {
logger.error("获取角色数据异常!", e);
outPut.setCode(OutputCodeConst.UNKNOWN_ERROR);
outPut.setMsg("获取角色数据异常! " + e.getMessage());
}
return JsonUtil.objectToJson(outPut);
}

服务端增加过滤拦截器(web.xml)

 <filter>
<filter-name>crossDomainFilter</filter-name>
<filter-class>com.luwei.core.filter.CrossDomainFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>crossDomainFilter</filter-name>
<url-pattern>*</url-pattern>
</filter-mapping>

服务端增加过滤拦截器(java)

 package com.luwei.core.filter;

 import java.io.IOException;

 import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import com.luwei.console.mg.constant.ApplicationConfiConst; /**
*
* <Description> TODO<br>
*
* @author lu.wei<br>
* @email 1025742048@qq.com <br>
* @date 2017年1月4日 <br>
* @since V1.0<br>
* @see com.luwei.console.mg.tag <br>
*/
public class CrossDomainFilter implements Filter {
private Logger logger = LoggerFactory.getLogger(getClass()); public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
ApplicationConfiConst confiConst = (ApplicationConfiConst) ContextUtil.getBean("applicationConfiConst");
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request = (HttpServletRequest) req;
String referer = request.getHeader("referer");
String origin = null;
if (null != referer) {
String[] domains = confiConst.getCanAccessDomain().split(",");
for (String domain : domains) {
if (StringUtils.isNotEmpty(domain) && referer.startsWith(domain)) {
origin = domain;
break;
}
}
}
response.setHeader("Access-Control-Allow-Origin", origin);
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE,PATCH");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
// 是否支持cookie跨域
response.addHeader("Access-Control-Allow-Credentials", "true"); String requestURI = ((HttpServletRequest) req).getRequestURI();
long begin = System.currentTimeMillis();
chain.doFilter(req, res);
if (logger.isDebugEnabled()) {
logger.debug("[Request URI: " + requestURI + "], Cost Time:" + (System.currentTimeMillis() - begin) + "ms");
}
}
}

增加设置能够通过跨域访问的服务器地址

#设置能够访问接口的域(多个通过都好分割)(不能配置127.0.0.1)
CAN_ACCESS_DOMAIN=http://localhost:8020,http://localhost:9999,http://localhost:8080

注意内容:

1、Ajax请求必须要设置withCredentials属性为true

withCredentials:true

2、服务端需要配置过滤器,讲配置能够进行跨域访问服务器的地址进行配置

response.setHeader("Access-Control-Allow-Origin", origin);
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE,PATCH");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
// 是否支持cookie跨域
response.addHeader("Access-Control-Allow-Credentials", "true");

3、withCredentials设置成true时,Access-Control-Allow-Origin不支持通过*的方式进行统配

4、Access-Control-Allow-Origin不能直接配置多个请求服务器,但是可以通过静态配置多个的方式,然后根据referer匹配,匹配到哪个则设置Access-Control-Allow-Origin为哪个的方式来配置多个

后记:

jqGrid配置跨域请求的方式为:

ajaxGridOptions: {
xhrFields: {
withCredentials: true
}
},

参考:

http://www.ruanyifeng.com/blog/2016/04/cors.html

http://www.cnblogs.com/dojo-lzz/p/4265637.html

JSONP和CORS两种跨域方式的简单介绍和解决方案实例的更多相关文章

  1. JSONP和CORS两种跨域方式的优缺点及使用方法原理介绍

    随着软件开发分工趋于精细,前后端开发分离成为趋势,前端同事负责前端页面的展示及页面逻辑处理,服务端同事负责业务逻辑处理同时通过API为前端提供数据也为前端提供数据的持久化能力,考虑到前后端同事开发工具 ...

  2. Javascript几种跨域方式总结

    在客户端编程语言中如javascript,同源策略规定跨域之间的脚本是隔离的,一个域的脚本不能访问和操作另外一个域的绝大部分属性和方法.只有当两个域具有相同的协议,相同的主机,相同的端口时,我们就认定 ...

  3. 从壹开始前后端分离【 .NET Core2.0 +Vue2.0 】框架之十二 || 三种跨域方式比较,DTOs(数据传输对象)初探

    更新反馈 1.博友@落幕残情童鞋说到了,Nginx反向代理实现跨域,因为我目前还没有使用到,给忽略了,这次记录下,为下次补充.此坑已填 2.提示:跨域的姊妹篇——<三十三║ ⅖ 种方法实现完美跨 ...

  4. Ajax操作如何实现跨域请求 (JSONP和CORS实现Ajax跨域的原理)

    由于浏览器存在同源策略机制,同源策略阻止ajax (XMLHttpRequest) 从一个源加载的文档或脚本获取或设置另一个源加载的文档的属性. 特别的:由于同源策略是浏览器的限制,所以请求的发送和响 ...

  5. jsonp的三种跨域方式

    1.通过jq的$.ajax()完成跨域,这是我比较喜欢的一种方式. 代码如下: $.ajax({ type:'get', async:true, url:'地址', dataType:'jsonp', ...

  6. 「JavaScript」JS四种跨域方式详解

    原文地址https://segmentfault.com/a/1190000003642057 超详细并且带 Demo 的 JavaScript 跨域指南来了! 本文基于你了解 JavaScript ...

  7. 「JavaScript」四种跨域方式详解

    超详细并且带 Demo 的 JavaScript 跨域指南来了! 本文基于你了解 JavaScript 的同源策略,并且了解使用跨域跨域的理由. 1. JSONP 首先要介绍的跨域方法必然是 JSON ...

  8. java web 的 几种跨域方式

  9. 允许浏览器跨域访问web服务端的解决方案

    今天和同事探讨了前后端如何真正实现隔离开发的问题,如果前端单独作为服务发布,势必会涉及到无法直接调用后端的接口的问题,因为浏览器是不允许跨域提交请求的. 所谓跨域访问,就是在浏览器窗口,和某个服务端通 ...

随机推荐

  1. ViewPager实现自动翻页功能 --转载出处找不到了,根据自己的理解写个随笔方便以后的记忆以及代码的共享,感谢给我启发的那位高手--第一次写博客哈

    xml文件 textview 用于显示图片的标题 viewpager 用于实现翻页效果 <LinearLayout xmlns:android="http://schemas.andr ...

  2. 完整的分页存储过程以及c#调用方法

    高效分页存储过程 USE [db] GO /****** 对象: StoredProcedure [dbo].[p_Page2005] 脚本日期: // :: ******/ SET ANSI_NUL ...

  3. Android深度探索--HAL与驱动开发----第八章读书笔记

    通过蜂鸣器的实现原理,实现一个完整的蜂呜器驱动,可以打开和关闭蜂鸣器. PWM驱动的实现方式不同于LED驱动, PWM 驱动将由多个文件组成.这也是大多数 Linux 驱动的标准实现方式. 刚开始是L ...

  4. UE4蓝图编程的第一步

    认识UE4蓝图中颜色与变量类型: UE4中各个颜色对应着不同的变量,连接点和连线的颜色都在表示此处是什么类型的变量.对于初学者来说一开始看到那么多连接点, 可能会很茫然,搞不清还怎么连,如果知道了颜色 ...

  5. 4 多表代替密码之Hill 密码 2实现

    该解密方法的KEY 不是一个数或者一段字符串,而是一个矩阵, 比如有个3*3的KEY: 那么如果我们要加密一个长度为N的字符串, 那么把N除以3,分成M个3个字母组成的小段, 对每个小段尽心加密: 1 ...

  6. 结构及其使用 struct (C#)

    首先结构是值类型. 结构是使用 struct 关键字定义的,结构如下: struct 结构名{} 结构概述 结构具有以下特点: 结构是值类型,而类是引用类型. (结构不能包含显式的无参数构造函数) 与 ...

  7. Linux覆盖率一点研究:获取覆盖率数据

     首先,当然哥不介意你鄙视我在网上找的资料研究! 白盒覆盖率是啥东东这个问题大家自己查百度啦!我也不太懂,就知道它不是个东西,就这样开始吧(MT一般是先摸四蹄呢还是先黑金币呢?这是个问题)! 首先:l ...

  8. A - Ice_cream’s world III

    Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Pract ...

  9. C#基础——全局静态类中的静态类变量的设置

    前言 今天在设计一个系统用户管理界面的时候,出现了一个问题: 由于要在不同窗体之间传递数据,所以想到了要设置全局变量,比如一个用户有属性,ID,UserName,UserPwd和UserPower,为 ...

  10. Windows Server 2012 没有远程桌面授权服务器可以提供许可证,远程会话被中断

    今天在登录公司内部的服务器的时候,无法进行远程访问. 弹出错误信息:没有远程桌面授权服务器可以提供许可证,远程会话被中断 经过网上的寻找,原来是server 2012 远程登录只提供120天的使用期限 ...