• 跨域?

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

  • 同源策略?

一般来说 a.com 的网页无法直接与 b.com的服务器沟通, 浏览器的同源策略限制从一个源加载的文档或脚本与来自另一个源的资源进行交互。

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

如果要在js里发起跨域请求,则要进行一些特殊处理了。或者,你可以把请求发到自己的服务端,通过后台代码发起请求,再将数据返回前端。(我几乎没有用到过jsonp,都是把跨域请求交给至高无上的服务端)

  • 解决问题的jsonp小概念出现了

浏览器端有可以直接跨域拿数据的,比如HTML 的<script> 元素。利用 <script> 元素的这个开放策略,网页可以得到从其他来源动态产生的 JSON 资料,而这种使用模式就是所谓的 JSONP。用 JSONP 抓到的资料并不是 JSON,而是任意的JavaScript,用 JavaScript 直译器执行后对数据用 JSON 解析器解析。

现在使用jsonp基本都是用ajax方式,来路是jquery将jsonp封装为ajax的一种形式,但它们的本质区别并不是跨域,ajax的核心通过XMLhttpRequest获取非本页内容,jsonp则是动态添加<script>标签来调用服务端js脚本.

  • 本文重点来了,小本本拿出来,考试要考哟~~~~~~

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

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

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

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

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

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

 1 <%@ page pageEncoding="utf-8" contentType="text/html;charset=UTF-8"  language="java" %>
2 <html>
3 <head>
4 <title>跨域测试</title>
5 <script src="js/jquery-1.7.2.js"></script>
6 <script>
7 $(document).ready(function () {
8
9 $("#btn").click(function () {
10 $.ajax({
11 url: 'http://localhost:9090/student',
12 type: 'GET',
13 success: function (data) {
14 $(text).val(data);
15 }
16 });
17
18 });
19
20 });
21 </script>
22 </head>
23 <body>
24 <input id="btn" type="button" value="跨域获取数据" />
25 <textarea id="text" style="width: 400px; height: 100px;"></textarea>
26 </body>
27 </html>

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

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

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

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

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

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

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

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

 1 <%@ page pageEncoding="utf-8" contentType="text/html;charset=UTF-8"  language="java" %>
2 <html>
3 <head>
4 <title>跨域测试</title>
5 <script src="js/jquery-1.7.2.js"></script>
6 <script>
7 //回调函数
8 function showData (result) {
9 var data = JSON.stringify(result); //json对象转成字符串
10 $("#text").val(data);
11 }
12
13 $(document).ready(function () {
14
15 $("#btn").click(function () {
16 //向头部输入一个脚本,该脚本发起一个跨域请求
17 $("head").append("<script src='http://localhost:9090/student?callback=showData'><\/script>");
18 });
19
20 });
21 </script>
22 </head>
23 <body>
24 <input id="btn" type="button" value="跨域获取数据" />
25 <textarea id="text" style="width: 400px; height: 100px;"></textarea>
26
27 </body>
28 </html>

服务端:

 1 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
2 response.setCharacterEncoding("UTF-8");
3 response.setContentType("text/html;charset=UTF-8");
4
5 //数据
6 List<Student> studentList = getStudentList();
7
8
9 JSONArray jsonArray = JSONArray.fromObject(studentList);
10 String result = jsonArray.toString();
11
12 //前端传过来的回调函数名称
13 String callback = request.getParameter("callback");
14 //用回调函数名称包裹返回数据,这样,返回数据就作为回调函数的参数传回去了
15 result = callback + "(" + result + ")";
16
17 response.getWriter().write(result);
18 }

结果:

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

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

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

 1 <%@ page pageEncoding="utf-8" contentType="text/html;charset=UTF-8"  language="java" %>
2 <html>
3 <head>
4 <title>跨域测试</title>
5 <script src="js/jquery-1.7.2.js"></script>
6 <script>
7
8 $(document).ready(function () {
9
10 $("#btn").click(function () {
11
12 $.ajax({
13 url: "http://localhost:9090/student",
14 type: "GET",
15 dataType: "jsonp", //指定服务器返回的数据类型
16 success: function (data) {
17 var result = JSON.stringify(data); //json对象转成字符串
18 $("#text").val(result);
19 }
20 });
21
22 });
23
24 });
25 </script>
26 </head>
27 <body>
28 <input id="btn" type="button" value="跨域获取数据" />
29 <textarea id="text" style="width: 400px; height: 100px;"></textarea>
30
31 </body>
32 </html>

效果:

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

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

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

 1 <%@ page pageEncoding="utf-8" contentType="text/html;charset=UTF-8"  language="java" %>
2 <html>
3 <head>
4 <title>跨域测试</title>
5 <script src="js/jquery-1.7.2.js"></script>
6 <script>
7
8 function showData (data) {
9 console.info("调用showData");
10
11 var result = JSON.stringify(data);
12 $("#text").val(result);
13 }
14
15 $(document).ready(function () {
16
17 // window.showData = function (data) {
18 // console.info("调用showData");
19 //
20 // var result = JSON.stringify(data);
21 // $("#text").val(result);
22 // }
23
24 $("#btn").click(function () {
25
26 $.ajax({
27 url: "http://localhost:9090/student",
28 type: "GET",
29 dataType: "jsonp", //指定服务器返回的数据类型
30 jsonpCallback: "showData", //指定回调函数名称
31 success: function (data) {
32 console.info("调用success");
33 }
34 });
35 });
36
37 });
38 </script>
39 </head>
40 <body>
41 <input id="btn" type="button" value="跨域获取数据" />
42 <textarea id="text" style="width: 400px; height: 100px;"></textarea>
43
44 </body>
45 </html>

效果图:

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

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

 1 <%@ page pageEncoding="utf-8" contentType="text/html;charset=UTF-8"  language="java" %>
2 <html>
3 <head>
4 <title>跨域测试</title>
5 <script src="js/jquery-1.7.2.js"></script>
6 <script>
7
8 function showData (data) {
9 console.info("调用showData");
10
11 var result = JSON.stringify(data);
12 $("#text").val(result);
13 }
14
15 $(document).ready(function () {
16
17 $("#btn").click(function () {
18
19 $.ajax({
20 url: "http://localhost:9090/student",
21 type: "GET",
22 dataType: "jsonp", //指定服务器返回的数据类型
23 jsonp: "theFunction", //指定参数名称
24 jsonpCallback: "showData", //指定回调函数名称
25 success: function (data) {
26 console.info("调用success");
27 }
28 });
29 });
30
31 });
32 </script>
33 </head>
34 <body>
35 <input id="btn" type="button" value="跨域获取数据" />
36 <textarea id="text" style="width: 400px; height: 100px;"></textarea>
37
38 </body>
39 </html>

后台代码:

 1 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
2 response.setCharacterEncoding("UTF-8");
3 response.setContentType("text/html;charset=UTF-8");
4
5 //数据
6 List<Student> studentList = getStudentList();
7
8
9 JSONArray jsonArray = JSONArray.fromObject(studentList);
10 String result = jsonArray.toString();
11
12 //前端传过来的回调函数名称
13 String callback = request.getParameter("theFunction");
14 //用回调函数名称包裹返回数据,这样,返回数据就作为回调函数的参数传回去了
15 result = callback + "(" + result + ")";
16
17 response.getWriter().write(result);
18 }

效果图:

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

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

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

 1 <%@ page pageEncoding="utf-8" contentType="text/html;charset=UTF-8"  language="java" %>
2 <html>
3 <head>
4 <title>跨域测试</title>
5 <script src="js/jquery-1.7.2.js"></script>
6 <script>
7
8 $(document).ready(function () {
9
10 $("#btn").click(function () {
11
12 $.ajax({
13 url: "http://localhost:9090/student",
14 type: "POST", //post请求方式
15 dataType: "jsonp",
16 jsonp: "callback",
17 success: function (data) {
18 var result = JSON.stringify(data);
19 $("#text").val(result);
20 }
21 });
22 });
23
24 });
25 </script>
26 </head>
27 <body>
28 <input id="btn" type="button" value="跨域获取数据" />
29 <textarea id="text" style="width: 400px; height: 100px;"></textarea>
30 </body>
31 </html>

效果图:

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

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

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

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

 1 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
2 response.setCharacterEncoding("UTF-8");
3 response.setContentType("text/html;charset=UTF-8");
4
5 // * 表示允许任何域名跨域访问
6 response.setHeader("Access-Control-Allow-Origin", "*");
7 // 指定特定域名可以访问
8 response.setHeader("Access-Control-Allow-Origin", "http:localhost:8080/");
9
10 //数据
11 List<Student> studentList = getStudentList();
12
13 JSONArray jsonArray = JSONArray.fromObject(studentList);
14 String result = jsonArray.toString();
15
16 //前端传过来的回调函数名称
17 String callback = request.getParameter("callback");
18 //用回调函数名称包裹返回数据,这样,返回数据就作为回调函数的参数传回去了
19 result = callback + "(" + result + ")";
20
21 response.getWriter().write(result);
22 }

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

原先自己总结的jsonp在看了这篇文章后觉得写得思路很乱,累赘也多, 原作者的这篇jsonp思路清晰,示例代码与页面都有详细标注与截图,很容易给新手了解,于是copy来,给自己笔记也给需要的猿猿们借鉴

原文作者:bojiangzhou  原文链接:http://www.cnblogs.com/chiangchou/

js跨域交互之jsonp - 看完就能让你了解jsonp原理 (原)的更多相关文章

  1. JS跨域(ajax跨域、iframe跨域)解决方法及原理详解(jsonp)

    这里说的js跨域是指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过js获取页面中不同域的框架中(iframe)的数据.只要协议.域名.端口有任何一个不同,都被 ...

  2. 【转】JS跨域(ajax跨域、iframe跨域)解决方法及原理详解(jsonp)

    这里说的js跨域是指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过js获取页面中不同域的框架中(iframe)的数据.只要协议.域名.端口有任何一个不同,都被 ...

  3. js跨域请求方式 ---- JSONP原理解析

    这篇文章主要介绍了js跨域请求的5中解决方式的相关资料,需要的朋友可以参考下     跨域请求数据解决方案主要有如下解决方法:   1 2 3 4 5 JSONP方式 表单POST方式 服务器代理 H ...

  4. JS跨域:jsonp、跨域资源共享、iframe+window.name

    JS跨域:jsonp.跨域资源共享.iframe+window.name :https://www.cnblogs.com/doudoublog/p/8652213.html JS中的跨域 请求跨域有 ...

  5. JS跨域请求 JSONP B/S全代码

    Ajax直接请求普通文件存在跨域无权限访问的问题,甭管你是静态页面.动态网页.web服务.WCF,只要是跨域请求,一律不准:Web页面上调用js文件时则不受是否跨域的影响(不仅如此,我们还发现凡是拥有 ...

  6. 初步了解关于js跨域问题-jsonp

    js跨域问题是指在js在不同的域中进行数据传输或者数据通信,比如通过ajax向不同的域请求数据(说到ajax,不可避免的就会遇到两个问题:一是ajax是如何传递数据的?二是ajax是如何实现跨域的?) ...

  7. js跨域请求jsonp解决方案-最简单的小demo

    这里说的js跨域是指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过js获取页面中不同域的框架中(iframe)的数据.只要协议.域名.端口有任何一个不同,都被 ...

  8. js跨域问题解释 使用jsonp或jQuery的解决方案

    js跨域及解决方案 1.什么是跨域 我们经常会在页面上使用ajax请求访问其他服务器的数据,此时,客户端会出现跨域问题. 跨域问题是由于javascript语言安全限制中的同源策略造成的. 简单来说, ...

  9. 【js跨域】js实现跨域访问的几种方式

    这里说的js跨域是指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过js获取页面中不同域的框架中(iframe)的数据.只要协议.域名.端口有任何一个不同,都被 ...

随机推荐

  1. [转]decorator(HTML装饰器)

    原文地址:https://blog.csdn.net/jzh440/article/details/7770013 1>:每当遇到一个新的技术,首先我会问自己,这个技术是做神马的?用这个技术有神 ...

  2. 【iCore4 双核心板_uC/OS-II】例程十一:内存管理

    一.实验说明: 应用程序在运行中为了某种特殊需要,经常需要临时获得一些内存空间.而作为比较完善的操作系统uC/OS-II,也具有动态分配内存的能力. uC/OS-II对内存进行两级管理:把连续内存分成 ...

  3. springmvc 拦截通配符 /** /

    /** 拦截所有 包括 *.js *.css *.png 等等 / 只拦截 /login, /logout, /index等等      

  4. R语言与机器学习学习笔记

    人工神经网络(ANN),简称神经网络,是一种模仿生物神经网络的结构和功能的数学模型或计算模型.神经网络由大量的人工神经元联结进行计算.大多数情况下人工神经网络能在外界信息的基础上改变内部结构,是一种自 ...

  5. IT观察】网络通信、图片显示、数据库操作……Android程序员如何利用开源框架

    每个Android 程序员都不是Android应用开发之路上孤军奋战的一个人,GitHub上浩如烟海的开源框架或类库就是前人为我们发明的轮子,有的轮子能提高软件性能,而有的轮子似乎是以牺牲性能为代价换 ...

  6. linux 使用不安全的sprintf函数,存储字符越界导致程序莫名崩溃问题

    linux c++编程 问题背景: 在处理一个公共模块的代码中,其中有以下代码片段 //代码片段-组合一组字符串并存放到szSignKey数组中 ] = {}; sprintf(szSignKey, ...

  7. 获取当前目录绝对路径,参考canal run.sh里面的方式

    case "`uname`" in Darwin) bin_abs_path=`cd $(dirname $0); pwd` ;; Linux) bin_abs_path=$(re ...

  8. Springboot中enable注解

    这句话可以作为理解springboot自动注入的原理的钥匙:ImportSelector接口的selectImports返回的数组(类的全类名)都会被纳入到spring容器中. 至于spring怎么根 ...

  9. 《Linux.Shell编程从入门到精通》读书笔记

    第一章 第一个Shell程序 以 #!解析器名称 开头,表示选择哪个解释器解释shell脚本 source命令 export命令 env命令 unset命令 第二章 shell编程基础 函数传递 标准 ...

  10. 在node环境使用axios发送文件

    yarn add form-data (async () => { const l = console.log; const axios = require("axios") ...