Jsonp跨域请求
来源:互联网 发布:sql 多个结果合并 编辑:程序博客网 时间:2024/06/04 19:58
什么是jsonp?为什么要用jsonp?JSONP(JSON with Padding)是JSON的一种“使用模式”,可用于解决主流浏览器的跨域数据访问的问题。由于同源策略,一般来说位于 server1.example.com 的网页无法与不是 server1.example.com的服务器沟通,而 HTML 的<script> 元素是一个例外。利用 <script> 元素的这个开放策略,网页可以得到从其他来源动态产生的 JSON 资料,而这种使用模式就是所谓的 JSONP。用 JSONP 抓到的资料并不是 JSON,而是任意的JavaScript,用 JavaScript 直译器执行而不是用 JSON 解析器解析。
以上是百度百科对于jsonp的解释,所谓"同源"指的是"相同协议相同端口"。
例如:h ttp://http://www.abc.com/test1 与以下url做同源检测
h ttps://http://www.abc.com/test2不同源(协议不同 http / https)
h ttp://http://www.abc.com:81/test3 不同源(端口不同 80 / 81)
h ttp://http://www.abc.com/test4 同源
注:ie"同源策略"不包括端口,即与 h ttp://http://www.abc.com:81/test3 也为同源
跨域请求的原理
我们做一个简单的测试!
我们在 h ttp://169.254.200.238:8020/jsonp/index.html下向
h ttp://169.254.200.238:8080/jsonp.do发起请求,
$.get("http://169.254.200.238:8080/jsonp.do", function (data) { console.log(data); });
此时浏览器抛出异常
因为两者的端口号分别为8080、8020 并不同源,从报错中也可以看出。
但是,我们换一种方式请求:
<script type="text/javascript" src="http://169.254.200.238:8080/jsonp.do"> </script>
可以看到,此时同样的请求确成功了!由此,我们可以得出<scrpit>可以进行跨域请求,这是jsonp的基础,但是浏览器同样抛出了语句不合法的异常,
那是因为我们请求的数据会立马被浏览器当作javascript语句去执行(谁让我们用<script>去请求数据呢),但是请求到的数据格式并不符合其语法规范。
那么,如何解决这一问题呢?
如果我们返回的内容符合javascript的语法规范呢?
所以,我们把请求的数据当作一个函数的参数,并且这个函数在客户端存在的话,那么这就行得通。
例如:请求返回的数据为
callback( {"result":"success"} )
其中{"result":"success"} 是我们想要获取的数据,浏览器会立即执行callback这个函数,此时,我们已经定义好了函数名为callback这个函数:
function callback(data){ // data为返回数据 // TODO 解析数据}
所以jsonp跨域请求的关键就在于:
服务端要在返回的数据外层包裹一个客户端已经定义好的函数
ajax跨域请求实例
理解了上述内容,你就已经掌握了跨域请求的原理,那么下面我们将利用ajax发起跨域请求,服务端通过spring MVC处理jsonp请求。
//通过JQuery Ajax 发起jsonp请求(注:不是必须通过jq发起请求 , 例如:Vue Resource中提供 $.http.jsonp(url, [options]))$.ajax({ // 请求方式 type: "get", // 请求地址 url: "http://169.254.200.238:8080/jsonp.do", // 标志跨域请求 dataType: "jsonp", // 跨域函数名的键值,即服务端提取函数名的钥匙(默认为callback) jsonp: "callbackparam", // 客户端与服务端约定的函数名称 jsonpCallback: "jsonpCallback", // 请求成功的回调函数,json既为我们想要获得的数据 success: function(json) { console.log(json); }, // 请求失败的回调函数 error: function(e) {alert("error"); }});
@RequestMapping({"/jsonp.do"})public String jsonp(@RequestParam("callbackparam") String callback){ // callback === "jsonpCallback"return callback + "({\"result\":\"success\"})";}
此时,客户端接收到的返回值为:
这就是一个完整的跨域请求,但是这样就结束了吗?
细心的同学可能会发觉,现在如果不通过跨域去请求jsonp.do这个接口,不是就报错了吗?
是的,现在这个接口仅仅只能被携带callbackparam这个参数的请求。
为了解决这个问题,我们要判断请求的来源,
return (request.from === jsonp) ? callback(data) : data ;
这才是我们想要的结果,解决这个问题需要我们对每个接口都做判断,或者通过AOP等等方式实现统一处理,这样做好像并不优雅。
在spring4.2以上的版本,支持了CORS(跨域资源共享)
CORS
CORS是一个W3C标准,全称是”跨域资源共享”(Cross-origin resource sharing)。
它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
为什么说它优雅呢?
整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
因此,实现CORS通信的关键是服务器。 只要服务器实现了CORS接口 ,就可以跨源通信。
所以我们客户端可以像什么都没发生一样,依旧漠不关心的发送我们的请求:
// 不用担心跨域问题$.ajax({ // 请求方式 type: "get", // 请求地址 url: "http://169.254.200.238:8080/jsonp.do", // 此时依然请求json格式数据 而非jsonp dataType: "json", // 请求成功的回调函数 success: function(json) { console.log(json); }, // 请求失败的回调函数 error: function(e) {alert("error"); }});
而我们用spring MVC实现的服务端也出乎意料的简洁(基于xml):
// spring配置文件 spring必须为4.2以上版本<mvc:cors> <mvc:mapping path="/**" /></mvc:cors>
注意:通过以上两步我们已经完成了跨域请求操作。
这里,我对整个项目添加了跨域支持 , path 为支持跨域的路径 , 同样你可以在这里做详细配置:
<mvc:cors> <mvc:mapping path="/api/**" allowed-origins="http://domain1.com, http://domain2.com" allowed-methods="GET, PUT" allowed-headers="header1, header2, header3" exposed-headers="header1, header2" allow-credentials="false" max-age="123" /> <mvc:mapping path="/resources/**" allowed-origins="http://domain1.com" /></mvc:cors>
当然,spring也支持通过java的方式进行配置:
// 此种方式等同于xml全局配置@Configurationpublic class WebConfig extends WebMvcConfigurerAdapter { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**"); }}// 此种方式为详细配置@Configurationpublic class WebConfig extends WebMvcConfigurerAdapter { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/api/**") .allowedOrigins("http://domain2.com") .allowedMethods("PUT", "DELETE") .allowedHeaders("header1", "header2", "header3") .exposedHeaders("header1", "header2") .allowCredentials(false).maxAge(3600); }}
spring 也允许针对某个controller类 或者 方法进行 跨域 ,通过@Configuration注解完成。
这里就不做详细解释,详情可以参考
SpringMvc解决跨域问题 - 王念博客 - 开源中国社区
编辑于 2016-12-15
- jsonp跨域请求
- jsonp 跨域请求
- jsonp跨域请求
- jsonp跨域请求
- jsonp跨域请求
- jsonp跨域请求
- JSONP 跨域请求
- jsonp跨域请求
- jsonp跨域请求
- JSONP跨域请求
- JsonP跨域请求
- jsonp跨域请求
- 跨域请求jsonp
- jsonp跨域请求
- JsonP跨域请求
- 跨域请求jsonp
- jsonp 跨域请求
- Jsonp跨域请求
- 51Nod-1624-取余最短路
- 如何控制回撤
- jsp基础
- Dockerfile注意事项
- spring jar作用
- Jsonp跨域请求
- 简单的手势判断
- 对弈(把九角距离转换为曼哈顿距离)
- hdu1251(字典Trie树)
- Android开发笔记(八十八)同步与加锁
- 【Spring】Spring Framework Reference Documentation中文版28
- python3.4 安装 pycrypto
- Java中GUI——JTable中鼠标监听的添加
- 你必须了解的RecyclerView的五大开源项目-解决上拉加载、下拉刷新和添加Header、Footer等问题