使用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 24 jQuery
jquery点赞功能实现代码 点个赞吧!
May 29 jQuery
JQuery form表单提交前验证单选框是否选中、删除记录时验证经验总结(整理)
Jun 09 jQuery
jQuery、layer实现弹出层的打开、关闭功能
Jun 28 jQuery
jQuery实现的弹幕效果完整实例
Sep 06 jQuery
利用jquery如何从json中读取数据追加到html中
Dec 01 jQuery
jQuery实现鼠标响应式透明度渐变动画效果示例
Feb 13 jQuery
jQuery扩展方法实现Form表单与Json互相转换的实例代码
Sep 05 jQuery
基于Bootstrap和JQuery实现动态打开和关闭tab页的实例代码
Jun 10 jQuery
jQuery zTree树插件的使用教程
Aug 16 jQuery
jQuery 查找元素操作实例小结
Oct 02 jQuery
jQuery实现视频展示效果
May 30 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获取后台Job管理的实现代码
2011/06/10 PHP
php文件上传的例子及参数详解
2013/12/12 PHP
PHP实现数组递归转义的方法
2014/08/28 PHP
php实现将字符串按照指定距离进行分割的方法
2015/03/14 PHP
PHP入门教程之操作符与控制结构流程详解
2016/09/09 PHP
关于php 高并发解决的一点思路
2017/04/16 PHP
php设计模式之工厂方法模式分析【星际争霸游戏案例】
2020/01/23 PHP
jQuery学习笔记之Helloworld
2010/12/22 Javascript
实现点击列表弹出列表索引的两种方式
2013/03/08 Javascript
页面载入结束自动调用js函数示例
2013/09/23 Javascript
javascript中验证大写字母、数字和中文
2014/01/15 Javascript
浅谈bootstrap源码分析之scrollspy(滚动侦听)
2016/06/06 Javascript
js实现3D图片环展示效果
2017/03/09 Javascript
整理关于Bootstrap表单的慕课笔记
2017/03/29 Javascript
jQuery序列化后的表单值转换成Json
2017/06/16 jQuery
从对象列表中获取一个对象的方法,依据关键字和值
2017/09/20 Javascript
php 解压zip压缩包内容到指定目录的实例
2018/01/23 Javascript
axios全局请求参数设置,请求及返回拦截器的方法
2018/03/05 Javascript
Angular8路由守卫原理和使用方法
2019/08/29 Javascript
Vuex中实现数据状态查询与更改
2019/11/08 Javascript
shelve  用来持久化任意的Python对象实例代码
2016/10/12 Python
python中abs&amp;map&amp;reduce简介
2018/02/20 Python
python库lxml在linux和WIN系统下的安装
2018/06/24 Python
Django 后台获取文件列表 InMemoryUploadedFile的例子
2019/08/07 Python
Pandas 解决dataframe的一列进行向下顺移问题
2019/12/27 Python
python读取xml文件方法解析
2020/08/04 Python
浅谈anaconda python 版本对应关系
2020/10/07 Python
Django Auth用户认证组件实现代码
2020/10/13 Python
移动端Web页面的CSS3 flex布局快速上手指南
2016/05/31 HTML / CSS
int和Integer有什么区别
2013/05/25 面试题
大一军训感言
2014/01/09 职场文书
小学敬老月活动方案
2014/02/11 职场文书
大学活动总结格式
2014/04/29 职场文书
小学模范班主任事迹材料
2014/05/13 职场文书
网吧温馨提示
2015/07/17 职场文书
教师听课学习心得体会
2016/01/15 职场文书