本文会代码层面对CORS问题进行剖析

CORS相关相关概念可参考http://www.cnblogs.com/softidea/p/5496719.html

ERROR info:

XMLHttpRequest cannot load http://localhost:8080/jsonp/scene1/user/1. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access.

JSONP(Javascript Object Notation With Padding)需要客户端和服务器支持

JSONP解释
在解释JSONP之前,我们需要了解下”同源策略“这个概念,这对理解跨域有帮助。
基于安全的原因,浏览器是存在同源策略机制的,同源策略阻止从一个源加载的文档或脚本获取或设置另一个源加载额文档的属性。有点绕,说的简单点就是浏览器限制脚本只能和同协议、同域名、同端口的脚本进行交互。

什么是jsonp格式呢?
API原文:
如果获取的数据文件存放在远程服务器上(域名不同,也就是跨域获取数据),则需要使用jsonp类型。
使用这种类型的话,会创建一个查询字符串参数 callback=? ,这个参数会加在请求的URL后面。
服务器端应当在JSON数据前加上回调函数名,以便完成一个有效的JSONP请求。

意思就是远程服务端需要对返回的数据做下处理,根据客户端提交的callback的参数,返回一个callback(json)的数据,而客户端将会用script的方式处理返回数据,来对json数据做处理。JQuery.getJSON也同样支持jsonp的数据方式调用。

JSONP就是为了解决这一问题的,JSONP是英文JSON with Padding的缩写,是一个非官方的协议。他允许服务端生成script tags返回值客户端,通过JavaScript callback的形式来实现站点访问。JSONP是一种script tag的注入,将server返回的response添加到页面是实现特定功能。
简而言之,JSONP本身不是复杂的东西,就是通过scirpt标签对javascript文档的动态解析绕过了浏览器的同源策略。
JSONP原理及实现
接下来,来实际模拟一个跨域请求的解决方案。后端为spring MVC架构的,前端则通过Ajax进行跨域访问。
1、首先客户端需要注册一个callback(服务端通过该callback(jsonp)可以得到js函数名(jsonpCallback)),然后以JavaScript语
法的方式,生成一个function
2、接下来,将JSON数据直接以入参的方式,放置到function中,这样就生成了一段js语法文档,返回给客户端。
3、最后客户端浏览器动态的解析script标签,并执行返回的JavaScript语法文档片段,此时数据作为参数传入到了预先定义好的
回调函数里(动态执行回调函数)。
这种动态解析js文档和eval函数是类似的。

 

客户端的支持:

This is how I'm using JSONP with Spring MVC, just modify it according to your needs:
on Server Side:
下例中服务器端处理参数名为“callback"的客户端数据,此数据在客户端的JS代码必须存在,可以指定参数值,也不可以不指定,如果不指定,会由浏览器自动生成
类似下面这种格式:

http://localhost:8080/jsonp/scene1/user/1?callback=jQuery3210430263573155826_1502264239363&time=1502265440209&_=1502264239364

@RequestMapping(value="/notes/callback.json", method=RequestMethod.GET)
public void jsonpCallback(@RequestParam("callback") String callback, HttpServletResponse response) {response.setContentType("text/javascript; charset=UTF-8");PrintWriter out = response.getWriter();out.print(callback + "(" + jsonDataString + ")");
}

On client side:

<script src="http://code.jquery.com/jquery-1.6.2.min.js"></script>
<script type="text/javascript">function yourfunction() {jQuery.getJSON("http://localhost:8080/notes/callback.json?callback=?", function(data) {alert(data.someParam);});
}</script>

指定callback参数对应的值:

$.ajax({url: "http://tonghuashuo.github.io/test/jsonp.txt",dataType: 'jsonp',jsonp: "callback",jsonpCallback: "dosomething"
})
.done(function(res) {console.log("success");console.log(res);
})
.fail(function(res) {console.log("error");console.log(res);
});

后端关键代码(以PHP为例)

$result   = "{'data':'JSONP Works'}"; // 这里省略了数据库查询等操作,直接给出返回值
$callback = $_GET['callback'];        // 最好加上判空和默认值,以防拿不到参数
echo $callback."(".$result.")";// 返回的结果
// dosomething({"data":"JSONP Works"});

将上述代码放到你本地localhost中,尝试运行一下,顺利的话应该会在浏览器的控制台中得到以下的内容:

> success
> Object {data: "JSONP Works"}

实际发送出来的完整请求长这样:http://tonghuashuo.github.io/test/jsonp.txt?callback=dosomething&_=1471419449018。,后面的随机字符串是jQuery加上的。

区别于常规的 AJAX 请求,这里真正需要关心的参数有以下 3 个

  • dataType: 'jsonp',用于表示这是一个 JSONP 请求。
  • jsonp: 'callback',用于告知服务器根据这个参数获取回调函数的名称,通常约定就叫 callback。
  • jsonpCallback: 'dosomething',指定我们自己的回调函数名称,也是前面callback参数的值。远程服务接受callback参数的值就不再是自动生成的回调名

其中jsonpCallback参数是可以省略的,jQuery 会自动生成一个随机字符串作为函数名,推荐这么做,以减少不必要的命名工作,同时排除潜在的安全隐患。这里由于Github Page没有后台服务,我们只能指定一个名字。注意:省略jsonpCallback的同时,jsonp参数必须指明,不能为false。

jQuery 还支持将jsonp设置为false以避免callback参数出现在请求 URL 中,但这需要前后端配合,前端必须要指定jsonpCallback的值为一个函数名,后端由于无法从请求中获取回调函数的名称,因此也必须固定使用同名的字符串进行拼接。

Spring 4 MVC + JSONP Example with REST, @ResponseBody and ResponseEntity
客户端代码示例:

$("#but1").click(function(){  $.ajax({  url:'http://127.0.0.1:8080/DevInfoWeb/get',  type: "get",  async: false,  dataType: "jsonp",  jsonp: "callbackparam", //服务端用于接收callback调用的function名的参数   jsonpCallback: "success_jsonpCallback", //callback的function名称,服务端会把名称和data一起传递回来   success: function(json) {  alert(json);  },  error: function(){alert('Error');}
});
});  

<script language="JavaScript">
$(document).ready(function() {$.ajax({url:'http://localhost:8080/test/getPopularity',dataType:'jsonp',success:function(data){console.log("返回Json:")console.log(data)}});
});
</script>

http://localhost:8080/test/getPopularity?callback=jsonp

In this page we will provide Spring 4 MVC and JSONP example with REST, @ResponseBody and ResponseEntity. JSONP is JSON with padding. It supports JavaScript code running in web browser to request data from a server in different domain which is normally prohibited because of same-origin policy. According to this policy a web browser can allow the script code of one web browser to access data from another web browser within the same domain. Same-origin policy is because of web application security model. But this policy is not forced to <script> tag by web browser. From here the role of JSONP comes into picture. JSONP allows to access data from different domain using <script> tag by web browser. If we have a URL as
http://localhost:8080/concretepage-1/book1?callback=myfunction
and if it throws the JSONP response as

myfunction({"bookName":"Godan","writer":"Premchand"});

then in another domain, we can use it as

<script src=" http://localhost:8080/concretepage-1/book1?callback=myfunction " type="application/javascript"> </script>

In our client code to access JSONP, there should already be a function named myfunction() defined in script code.
To throw the JSONP response using spring, it provides AbstractJsonpResponseBodyAdvice class which is implemented by a class annotated with @ControllerAdvice.

Spring 4 Support for JSONP with AbstractJsonpResponseBodyAdvice
Find the our class which will support JSONP response.
JsonpAdvice.java

@ControllerAdvice
public class JsonpAdvice extends AbstractJsonpResponseBodyAdvice {public JsonpAdvice() {super("callback");}
} 

In the constructor, we need to call super method passing a key. This key will be used in query string of URL while requesting JSONP data. The above method facilitates REST web service to respond JSONP data and also controller method which respond using @ResponseBody and ResponseEntity.
JSONP with Spring REST
Find the bean being used in the example to generate JSON.
Book.java

public class Book {private String bookName;private String writer;public String getBookName() {return bookName;}public void setBookName(String bookName) {this.bookName = bookName;}public String getWriter() {return writer;}public void setWriter(String writer) {this.writer = writer;}
} 

We are creating a web service which will respond JSONP.
BookService.java

@RestController
class BookService {@RequestMapping(value= "/book1", produces = MediaType.APPLICATION_JSON_VALUE)Book bookInfo1() {Book book = new Book();book.setBookName("Godan");book.setWriter("Premchand");return book;}
} 

When we access the URL http://localhost:8080/concretepage-1/book1?callback=functionCall, it will throw the response as

functionCall({"bookName":"Godan","writer":"Premchand"});

JSONP with @ResponseBody and ResponseEntity
Now find a controller in which we have created methods that will return @ResponseBody and ResponseEntity.

@Controller
class BookController {@RequestMapping(value ="/book2", produces =MediaType.APPLICATION_JSON_VALUE )@ResponseBodyBook bookInfo2() {Book book = new Book();book.setBookName("Ramcharitmanas");book.setWriter("TulasiDas");return book;}@RequestMapping(value ="/book3", produces =MediaType.APPLICATION_JSON_VALUE )public ResponseEntity<Book> bookInfo3() {Book book = new Book();book.setBookName("Ramayan");book.setWriter("Valmiki");return ResponseEntity.accepted().body(book);}
} 

When we access the URL http://localhost:8080/concretepage-1/book2?callback=functionCall, we will get the output in browser as

functionCall({"bookName":"Ramcharitmanas","writer":"TulasiDas"});

And for the URL http://localhost:8080/concretepage-1/book3?callback=functionCall , the output will be

functionCall({"bookName":"Ramayan","writer":"Valmiki"});

JSONP Client Code
Now we will write client code which can be used in any other domain.
jsonptest.html

<html><head><script>function functionCall(data) {   console.log(data.bookName);console.log(data.writer);console.log('-----------');}</script></head><body><!-- Using REST URL--><script src="http://localhost:8080/concretepage-1/book1?callback=functionCall" type="application/javascript"> </script><!--Using @ResponseBody --><script src="http://localhost:8080/concretepage-1/book2?callback=functionCall" type="application/javascript"> </script><!--Using ResponseEntity --><script src="http://localhost:8080/concretepage-1/book3?callback=functionCall" type="application/javascript"> </script></body>
</html> 

Run this page and check the output in console.

在Firefox,chrome,opera,safari,ie9,ie8等高级浏览器直接可以用JSON对象的stringify()和parse()方法。
JSON.stringify(obj)将JSON转为字符串。JSON.parse(string)将字符串转为JSON格式;
上面的转换可以这么写:
var a={"name":"tom","sex":"男","age":"24"};
var b='{"name":"Mike","sex":"女","age":"29"}';
var aToStr=JSON.stringify(a);
var bToObj=JSON.parse(b);
alert(typeof(aToStr)); //string
alert(typeof(bToObj));//object

代码示例:

https://github.com/helloworldtang/cors-demo

参考:
http://www.cnblogs.com/softidea/p/3907113.html

http://blog.csdn.net/u010537398/article/details/52012548

https://en.wikipedia.org/wiki/JSONP

https://stackoverflow.com/questions/10323625/how-to-support-jsonp-with-spring-mvc-and-multiple-response-types

https://tonghuashuo.github.io/blog/jsonp.html

http://www.concretepage.com/spring-4/spring-4-mvc-jsonp-example-with-rest-responsebody-responseentity

http://blog.csdn.net/caiwenfeng_for_23/article/details/45300739

http://www.jianshu.com/p/983642ad125a

http://www.codesnoopy.com/2016/07/09/%E7%94%A8Spring-MVC-4%E5%AE%9E%E7%8E%B0jsonp%E8%B7%A8%E5%9F%9F%E8%B0%83%E7%94%A8/

https://my.oschina.net/u/130771/blog/52912

CORS 实战 专题相关推荐

  1. 北科院分子互作实战专题培训班(10月底/11月底班)(生物医药与营养健康协同创新中心)...

    北京市科学技术研究院 生物医药与营养健康协同创新中心 生命健康前沿培训基地 培训基地将以京津冀协同为战略契机,围绕国内外生物医药与营养健康领域的知识链.技术链与产业链的前沿培训与协同交流需求,组织高端 ...

  2. arcpy.mapping实战-专题图制图自动化

    arcpy.mapping实战-专题图制图自动化 by 李远祥 最初对arcpy.mapping感兴趣是因为一次大规模的专题地图调整的需要,由于某某单位利用ArcEngine编写的专题图出图系统,出现 ...

  3. 数据结构视频教程 -《数据结构深度实战专题班 C语言版(国嵌 唐老师主讲)(非常犀利)》

    整个视频打包下载地址:史上最全的数据结构视频教程系列分享之<数据结构深度实战专题班 C语言版(国嵌 唐老师主讲)(非常犀利)>,转载请保留出处和链接! 更多优秀资源请访问:我是码农 在计算 ...

  4. 小滴课堂-新版JavaWeb零基础到实战专题课程-9

    目录 前言 第九章 玩转会话跟踪技术Cookie 和 session 第1集 会话跟踪技术之什么是Cookie 第2集 javaweb开发核心之Cookie实战 第3集 Web开发必备知识之Sessi ...

  5. Linux中级实战专题篇:LVS负载均衡集群部署

    LVS负载均衡 一,负载均衡集群相关介绍 1,集群是什么 集群(cluster)技术是一种较新的技术,通过集群技术,可以在付出较低成本的情况下获得在性能.可靠性.灵活性方面的相对较高的收益,其任务调度 ...

  6. 数据结构深度实战专题班 C语言版(国嵌 唐老师主讲)(非常犀利)

    在计算机科学中,数据结构是一门研究非数值计算的程序设计问题中计算机的操作对象(数据元素)以及它们之间的关系和运算等的学科,数据结构是计算机专业的必修课程之一,也是编写高性能算法的必要前提.本视频教程的 ...

  7. Linux中级实战专题篇三:nginx服务(日志介绍,作用域,格式定义,流量控制,访问控制模块,用户信任登录)

    Nginx 日志配置 1.Nginx 日志介绍 Nginx 有一个非常灵活的日志记录模式,每个级别的配置可以有各自独立的访问日志, 所需日志模块 ngx_http_log_module 的支持,日志格 ...

  8. 【朝夕Net社区技术专刊】Core3.1 WebApi集群实战专题-Corre3.1WebApi配置集成日志/配置Swagger...

    欢迎大家阅读<朝夕Net社区技术专刊>第2期 我们致力于.NetCore的推广和落地,为更好的帮助大家学习,方便分享干货,特创此刊!很高兴你能成为首期读者,文末福利不要错过哦!本文通过3大 ...

  9. 【朝夕Net社区技术专刊】Core3.1 WebApi集群实战专题---WebApi环境搭建运行发布部署篇...

    欢迎大家阅读<朝夕Net社区技术专刊>第1期 我们致力于.NetCore的推广和落地,为更好的帮助大家学习,方便分享干货,特创此刊!很高兴你能成为首期读者,文末福利不要错过哦!本文通过5大 ...

最新文章

  1. 一、Linux Shell基础
  2. 【读书笔记】iOS-NSString的length
  3. 高性能jdbc封装工具 Apache Commons DbUtils 1.6(转载)
  4. 值得学习练手的22个Python迷你程序(附代码)
  5. 【Linux】一步一步学Linux——echo命令(203)
  6. Android 驱动(5)---MTK 平台分区表
  7. 使用Windows 7 管理Windows 2008 R2
  8. sas 安装后处理出错
  9. c语言的sin cos是弧度,C++中cos,sin,asin,acos這些三角函數操作的是弧度,而非角度(轉)...
  10. 用无线热点入门树莓派4详解
  11. php中$$代表什么意思
  12. 简单三招,教你做个app
  13. 管理Linux 系统的用户与用户组
  14. 子网掩码取反怎么取_关于子网掩码的问题
  15. 联想笔记本声音太小怎么办_电脑声音特别的小是怎么回事?我的笔记本
  16. torch.bernoulli 的使用方法(附代码示例)
  17. 第72届英国影艺学院电影奖9日公布入围名单
  18. 应用Bulter-Volmer方程与Monte Carlo 模型分析CO电氧化动力学
  19. Python:枚举法
  20. JavaScript操作摄像头指南

热门文章

  1. easyui中dialog的常犯错误
  2. 安全网关之三:IPTables
  3. GNU make manual 翻译(七十三)
  4. MySQL操作实战(三):表联结
  5. Linux目录结构介绍
  6. wxpython 安装教程
  7. jquery通过ajax向后台发送(checkbox)数组,并在后台接收,(发送的数据是checkedbox)...
  8. Printk与sched_clock_init的一点分析
  9. c# json使用集
  10. 统计学习方法 第一章 学习心得