使用jquery的jsonp如何发起跨域请求及其原理详解


Posted in jQuery onAugust 17, 2017

前言

本文主要给大家介绍的是关于jquery jsonp发起跨域请求及其原理的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍:

跨域的安全限制都是对浏览器端来说的,服务器端是不存在跨域安全限制的。

浏览器的同源策略限制从一个源加载的文档或脚本与来自另一个源的资源进行交互。

如果协议,端口和主机对于两个页面是相同的,则两个页面具有相同的源,否则就是不同源的。

如果要在js里发起跨域请求,则要进行一些特殊处理了。或者,你可以把请求发到自己的服务端,再通过后台代码发起请求,再将数据返回前端。

这里讲下使用jquery的jsonp如何发起跨域请求及其原理。

先看下准备环境:两个端口不一样,构成跨域请求的条件。

获取数据:获取数据的端口为9090

使用jquery的jsonp如何发起跨域请求及其原理详解

请求数据:请求数据的端口为8080

使用jquery的jsonp如何发起跨域请求及其原理详解

1、先看下直接发起ajax请求会怎么样

下面是发起请求端的代码:

<%@ page pageEncoding="utf-8" contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
 <title>跨域测试</title>
 <script src="js/jquery-1.7.2.js"></script>
 <script>
 $(document).ready(function () {
  
  $("#btn").click(function () {
  $.ajax({
   url: 'http://localhost:9090/student',
   type: 'GET',
   success: function (data) {
   $(text).val(data);
   }
  });

  });
  
 });
 </script>
</head>
<body>
 <input id="btn" type="button" value="跨域获取数据" />
 <textarea id="text" style="width: 400px; height: 100px;"></textarea>
</body>
</html>

请求的结果如下图:可以看到跨域请求因为浏览器的同源策略被拦截了。

使用jquery的jsonp如何发起跨域请求及其原理详解

2、接下来看如何发起跨域请求。解决跨域请求的方式有很多,这里只说一下jquery的jsop方式及其原理。

首先我们需要明白,在页面上直接发起一个跨域的ajax请求是不可以的,但是,在页面上引入不同域上的js脚本却是可以的,就像你可以在自己的页面上使用<img src=""> 标签来随意显示某个域上的图片一样。

比如我在8080端口的页面上请求一个9090端口的图片:可以看到直接通过src跨域请求是可以的。

使用jquery的jsonp如何发起跨域请求及其原理详解

3、那么看下如何使用<script src="">来完成一个跨域请求:

当点击"跨域获取数据"的按钮时,添加一个<script>标签,用于发起跨域请求;注意看请求地址后面带了一个callback=showData的参数;

showData即是回调函数名称,传到后台,用于包裹数据。数据返回到前端后,就是showData(result)的形式,因为是script脚本,所以自动调用showData函数,而result就是showData的参数。

至此,我们算是跨域把数据请求回来了,但是比较麻烦,需要自己写脚本发起请求,然后写个回调函数处理数据,不是很方便。

<%@ page pageEncoding="utf-8" contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
 <title>跨域测试</title>
 <script src="js/jquery-1.7.2.js"></script>
 <script>
 //回调函数
 function showData (result) {
  var data = JSON.stringify(result); //json对象转成字符串
  $("#text").val(data);
 }

 $(document).ready(function () {

  $("#btn").click(function () {
  //向头部输入一个脚本,该脚本发起一个跨域请求
  $("head").append("<script src='http://localhost:9090/student?callback=showData'><\/script>");
  });

 });
 </script>
</head>
<body>
 <input id="btn" type="button" value="跨域获取数据" />
 <textarea id="text" style="width: 400px; height: 100px;"></textarea>

</body>
</html>

服务端:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 response.setCharacterEncoding("UTF-8");
 response.setContentType("text/html;charset=UTF-8");

 //数据
 List<Student> studentList = getStudentList();


 JSONArray jsonArray = JSONArray.fromObject(studentList);
 String result = jsonArray.toString();

 //前端传过来的回调函数名称
 String callback = request.getParameter("callback");
 //用回调函数名称包裹返回数据,这样,返回数据就作为回调函数的参数传回去了
 result = callback + "(" + result + ")";

 response.getWriter().write(result);
}

结果:

使用jquery的jsonp如何发起跨域请求及其原理详解

4、再来看jquery的jsonp方式跨域请求:

服务端代码不变,js代码如下:最简单的方式,只需配置一个dataType:'jsonp' ,就可以发起一个跨域请求。jsonp指定服务器返回的数据类型为jsonp格式,可以看发起的请求路径,自动带了一个callback=xxx,xxx是jquery随机生成的一个回调函数名称。

这里的success就跟上面的showData一样,如果有success函数则默认success()作为回调函数。

<%@ page pageEncoding="utf-8" contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
 <title>跨域测试</title>
 <script src="js/jquery-1.7.2.js"></script>
 <script>

 $(document).ready(function () {

  $("#btn").click(function () {

  $.ajax({
   url: "http://localhost:9090/student",
   type: "GET",
   dataType: "jsonp", //指定服务器返回的数据类型
   success: function (data) {
   var result = JSON.stringify(data); //json对象转成字符串
   $("#text").val(result);
   }
  });

  });

 });
 </script>
</head>
<body>
 <input id="btn" type="button" value="跨域获取数据" />
 <textarea id="text" style="width: 400px; height: 100px;"></textarea>

</body>
</html>

效果:

使用jquery的jsonp如何发起跨域请求及其原理详解

再看看如何指定特定的回调函数:第30行代码

回调函数你可以写到<script>下(默认属于window对象),或者指明写到window对象里,看jquery源码,可以看到jsonp调用回调函数时,是调用的window.callback

然后看调用结果,发现,请求时带的参数是:callback=showData;调用回调函数的时候,先调用了指定的showData,然后再调用了success。所以,success是返回成功后必定会调用的函数,就看你怎么写了。

<%@ page pageEncoding="utf-8" contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
 <title>跨域测试</title>
 <script src="js/jquery-1.7.2.js"></script>
 <script>

 function showData (data) {
  console.info("调用showData");

  var result = JSON.stringify(data);
  $("#text").val(result);
 }

 $(document).ready(function () {

//  window.showData = function (data) {
//  console.info("调用showData");
//
//  var result = JSON.stringify(data);
//  $("#text").val(result);
//  }

  $("#btn").click(function () {

  $.ajax({
   url: "http://localhost:9090/student",
   type: "GET",
   dataType: "jsonp", //指定服务器返回的数据类型
   jsonpCallback: "showData", //指定回调函数名称
   success: function (data) {
   console.info("调用success");
   }
  });
  });

 });
 </script>
</head>
<body>
 <input id="btn" type="button" value="跨域获取数据" />
 <textarea id="text" style="width: 400px; height: 100px;"></textarea>

</body>
</html>

效果图:

使用jquery的jsonp如何发起跨域请求及其原理详解

使用jquery的jsonp如何发起跨域请求及其原理详解

再看看如何改变callback这个名称:第23行代码

指定callback这个名称后,后台也需要跟着更改。

<%@ page pageEncoding="utf-8" contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
 <title>跨域测试</title>
 <script src="js/jquery-1.7.2.js"></script>
 <script>

 function showData (data) {
  console.info("调用showData");

  var result = JSON.stringify(data);
  $("#text").val(result);
 }

 $(document).ready(function () {

  $("#btn").click(function () {

  $.ajax({
   url: "http://localhost:9090/student",
   type: "GET",
   dataType: "jsonp", //指定服务器返回的数据类型
   jsonp: "theFunction", //指定参数名称
   jsonpCallback: "showData", //指定回调函数名称
   success: function (data) {
   console.info("调用success");
   }
  });
  });

 });
 </script>
</head>
<body>
 <input id="btn" type="button" value="跨域获取数据" />
 <textarea id="text" style="width: 400px; height: 100px;"></textarea>

</body>
</html>

后台代码:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 response.setCharacterEncoding("UTF-8");
 response.setContentType("text/html;charset=UTF-8");

 //数据
 List<Student> studentList = getStudentList();


 JSONArray jsonArray = JSONArray.fromObject(studentList);
 String result = jsonArray.toString();

 //前端传过来的回调函数名称
 String callback = request.getParameter("theFunction");
 //用回调函数名称包裹返回数据,这样,返回数据就作为回调函数的参数传回去了
 result = callback + "(" + result + ")";

 response.getWriter().write(result);
}

效果图:

使用jquery的jsonp如何发起跨域请求及其原理详解

最后看看jsonp是否支持POST方式:ajax请求指定POST方式

可以看到,jsonp方式不支持POST方式跨域请求,就算指定成POST方式,会自动转为GET方式;而后端如果设置成POST方式了,那就请求不了了。

jsonp的实现方式其实就是<script>脚本请求地址的方式一样,只是ajax的jsonp对其做了封装,所以可想而知,jsonp是不支持POST方式的。

<%@ page pageEncoding="utf-8" contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
 <title>跨域测试</title>
 <script src="js/jquery-1.7.2.js"></script>
 <script>

 $(document).ready(function () {

  $("#btn").click(function () {

  $.ajax({
   url: "http://localhost:9090/student",
   type: "POST", //post请求方式
   dataType: "jsonp",
   jsonp: "callback",
   success: function (data) {
   var result = JSON.stringify(data);
   $("#text").val(result);
   }
  });
  });

 });
 </script>
</head>
<body>
 <input id="btn" type="button" value="跨域获取数据" />
 <textarea id="text" style="width: 400px; height: 100px;"></textarea>
</body>
</html>

效果图:

使用jquery的jsonp如何发起跨域请求及其原理详解

使用jquery的jsonp如何发起跨域请求及其原理详解

再补充一点,回到第一条:CORS头缺少“Access-Control-Allow-Origin”

有时候你会发现其它都没问题,出现这个错误:这个错误代表服务端拒绝跨域访问。如果出现这个错误,就需要在服务端设置允许跨域请求。

response.setHeader("Access-Control-Allow-Origin", "*"); 设置允许任何域名跨域访问

使用jquery的jsonp如何发起跨域请求及其原理详解

设置可以跨域访问:第6行代码或第8行代码,设置其中一个即可。

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 response.setCharacterEncoding("UTF-8");
 response.setContentType("text/html;charset=UTF-8");

 // * 表示允许任何域名跨域访问
 response.setHeader("Access-Control-Allow-Origin", "*");
 // 指定特定域名可以访问
 response.setHeader("Access-Control-Allow-Origin", "http:localhost:8080/");

 //数据
 List<Student> studentList = getStudentList();

 JSONArray jsonArray = JSONArray.fromObject(studentList);
 String result = jsonArray.toString();

 //前端传过来的回调函数名称
 String callback = request.getParameter("callback");
 //用回调函数名称包裹返回数据,这样,返回数据就作为回调函数的参数传回去了
 result = callback + "(" + result + ")";

 response.getWriter().write(result);
}

总结

jQuery ajax方式以jsonp类型发起跨域请求,其原理跟<script>脚本请求一样,因此使用jsonp时也只能使用GET方式发起跨域请求。跨域请求需要服务端配合,设置callback,才能完成跨域请求。

好了,以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

jQuery 相关文章推荐
jquery实现静态搜索功能(可输入搜索文字)
Mar 28 jQuery
jquery实现tab键进行选择后enter键触发click行为
Mar 29 jQuery
jQuery用noConflict代替$的实现方法
Apr 12 jQuery
js案例之鼠标跟随jquery版(实例讲解)
Jul 21 jQuery
jQuery实现腾讯信用界面(自制刻度尺)样式
Aug 15 jQuery
jQuery Collapse1.1.0折叠插件简单使用
Aug 28 jQuery
jQuery 防止相同的事件快速重复触发方法
Feb 08 jQuery
jQuery实现滚动到底部时自动加载更多的方法示例
Feb 18 jQuery
jQuery实现模拟搜索引擎的智能提示功能简单示例
Jan 27 jQuery
AJAX在JQuery中的应用详解
Jan 30 jQuery
javascript(基于jQuery)实现鼠标获取选中的文字示例【测试可用】
Oct 26 jQuery
jQuery ajax - getScript() 方法和getJSON方法
May 14 jQuery
jQuery的时间datetime控件在AngularJs中的使用实例(分享)
Aug 17 #jQuery
jQuery实现全选、反选和不选功能
Aug 16 #jQuery
jQuery取得元素标签名称小结(附代码)
Aug 16 #jQuery
深入研究jQuery图片懒加载 lazyload.js使用方法
Aug 16 #jQuery
jQuery中each循环的跳出和结束实例
Aug 16 #jQuery
基于JQuery的Ajax方法使用详解
Aug 16 #jQuery
jquery获取链接地址和跳转详解(推荐)
Aug 15 #jQuery
You might like
php4的session功能评述(二)
2006/10/09 PHP
PHP错误抑制符(@)导致引用传参失败Bug的分析
2011/05/02 PHP
配置php网页显示各种语法错误
2013/09/23 PHP
php的ajax简单实例
2014/02/27 PHP
Linux系统下PHP-FPM的安装和配置教程
2015/08/17 PHP
PHP单态模式简单用法示例
2016/11/16 PHP
DOM2非标准但却支持很好的几个属性小结
2012/01/21 Javascript
jquery js 重置表单 reset()具体实现代码
2013/08/05 Javascript
JavaScript中for-in遍历方式示例介绍
2014/02/11 Javascript
浅析javascript的间隔调用和延时调用
2014/11/12 Javascript
在Javascript中处理数组之toSource()方法的使用
2015/06/09 Javascript
js文字横向滚动特效
2015/11/11 Javascript
第九章之路径分页标签与徽章组件
2016/04/25 Javascript
url中的特殊符号有什么含义(推荐)
2016/06/17 Javascript
WEB 前端开发中防治重复提交的实现方法
2016/10/26 Javascript
JS 实现随机验证码功能
2017/02/15 Javascript
vue组件实现弹出框点击显示隐藏效果
2020/10/26 Javascript
Vue父子组建的简单通信之控制开关Switch的实现
2018/06/04 Javascript
vue中引用swiper轮播插件的教程详解
2018/08/16 Javascript
javascript中的闭包概念与用法实践分析
2019/07/26 Javascript
JS数据类型判断的几种常用方法
2020/07/07 Javascript
解决Can't find variable: SockJS vue项目的问题
2020/09/22 Javascript
linux系统使用python监控apache服务器进程脚本分享
2014/01/15 Python
使用python生成目录树
2018/03/29 Python
Python3 列表,数组,矩阵的相互转换的方法示例
2019/08/05 Python
Python3.7实现验证码登录方式代码实例
2020/02/14 Python
python属于哪种语言
2020/08/16 Python
HTML5文档结构标签
2017/04/21 HTML / CSS
英国简约舒适女装品牌:Great Plains
2018/07/27 全球购物
德国净水壶和滤芯品牌:波尔德PearlCo(家用净水器)
2020/04/29 全球购物
先进班级集体事迹材料
2014/01/30 职场文书
网上祭先烈心得体会
2014/09/01 职场文书
高中升旗仪式演讲稿
2014/09/09 职场文书
小学生2014国庆节演讲稿:祖国在我心中
2014/09/21 职场文书
优秀教研组申报材料
2014/12/26 职场文书
小公司融资,商业计划书的8切记
2019/07/15 职场文书