使用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中clone()函数实现表单中增加和减少输入项
May 13 jQuery
jQuery实现动态给table赋值的方法示例
Jul 04 jQuery
jquery在vue脚手架中的使用方式示例
Aug 29 jQuery
jQuery plugin animsition使用小结
Sep 14 jQuery
jQuery中内容过滤器简单用法示例
Mar 31 jQuery
jQuery实现带右侧索引功能的通讯录示例【附源码下载】
Apr 17 jQuery
深入浅析angular和vue还有jquery的区别
Aug 13 jQuery
jquery 动态遍历select 赋值的实例
Sep 12 jQuery
使用jquery Ajax实现上传附件功能
Oct 23 jQuery
Easyui 关闭jquery-easui tab标签页前触发事件的解决方法
Apr 28 jQuery
jQuery实现鼠标移入显示蒙版效果
Jan 11 jQuery
9种方法优化jQuery代码详解
Feb 04 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
php中选择什么接口(mysql、mysqli)访问mysql
2013/02/06 PHP
php通过字符串调用函数示例
2014/03/02 PHP
PHP整数取余返回负数的相关解决方法
2014/05/15 PHP
PHP实现文件上传和多文件上传
2015/12/24 PHP
Yii2框架实现数据库常用操作总结
2017/02/08 PHP
PHP addAttribute()函数讲解
2019/02/03 PHP
jquery实现仿新浪微博带动画效果弹出层代码(可关闭、可拖动)
2015/10/12 Javascript
JavaScript 七大技巧(二)
2015/12/13 Javascript
JavaScript中的this机制
2016/01/30 Javascript
AngularJS ng-blur 指令详解及简单实例
2016/07/30 Javascript
AngularJS基础 ng-list 指令详解及示例代码
2016/08/02 Javascript
jquery实现全选、不选、反选的两种方法
2016/09/06 Javascript
Vue.js进行查询操作的实例详解
2017/08/25 Javascript
深入理解使用Vue实现Context-Menu的思考与总结
2019/03/09 Javascript
js事件机制----捕获与冒泡机制实例分析
2020/05/22 Javascript
[01:00:06]加油DOTA_EP01_网络版
2014/08/09 DOTA
python协程用法实例分析
2015/06/04 Python
python机器学习库常用汇总
2017/11/15 Python
Python基于socket实现简单的即时通讯功能示例
2018/01/16 Python
Python基于递归算法实现的汉诺塔与Fibonacci数列示例
2018/04/18 Python
Linux下python与C++使用dlib实现人脸检测
2018/06/29 Python
python生成密码字典的方法
2018/07/06 Python
Python OpenCV利用笔记本摄像头实现人脸检测
2020/08/20 Python
django框架事务处理小结【ORM 事务及raw sql,customize sql 事务处理】
2019/06/27 Python
pycharm无法导入本地模块的解决方式
2020/02/12 Python
keras 使用Lambda 快速新建层 添加多个参数操作
2020/06/10 Python
法国太阳镜店:Sunglasses Shop
2016/08/27 全球购物
adidas泰国官网:adidas TH
2020/07/11 全球购物
FragranceNet中文网:北美健康美容线上零售商
2020/08/26 全球购物
DataReader和DataSet的异同
2014/12/31 面试题
党章学习思想汇报
2014/01/14 职场文书
2014年会计主管工作总结
2014/12/20 职场文书
银行求职信模板
2015/03/20 职场文书
2015年度个人思想工作总结
2015/04/08 职场文书
给女朋友的道歉短信
2015/05/12 职场文书
《正比例》教学反思
2016/02/23 职场文书