本篇主要讨论JSONP和CORS这两种技术,使用它们的原因是为了完成对资源的跨域访问,也就是如何绕过浏览器的同源策略Same-origin Policy

那么什么是Same-origin Policy呢?简单地说,在一个浏览器中访问的网站不能访问另一个网站中的数据,除非这两个网站具有相同的Origin,也即是拥有相同的协议、主机地址以及端口。一旦这三项数据中有一项不同,那么该资源就将被认为是从不同的Origin得来的,进而不被允许访问。

特别的:由于同源策略是浏览器的限制,所以请求的发送和响应是可以进行,只不过浏览器不接受罢了。

浏览器同源策略并不是对所有的请求均制约:

  • 制约: XmlHttpRequest
  • 不叼: img、iframe、script等具有src属性的标签

解决方案:

  1、-requests发请求时,跨域无限制

  2、- ajax发请求时,浏览器限制【是否可以绕过限制?】

      -JSONP

      -CORS

requests模块当然可以通过跨域:

 #####服务端(urls.py)######

 urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^get_data.html/$', views.get_data),
]
 ######服务端(views.py)######
from django.shortcuts import render,HttpResponse def get_data(request):
return HttpResponse(‘机密文件’)
 #####客户端(views.py)######

 def index(request):
# 方式一:requests模块
import requests
response=requests.get("http://127.0.0.1:8000/get_data.html/")
return render(request,"index.html",{"response":response})
 #####客户端(index.html)#######

 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="x-ua-compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Title</title>
<script src="/static/jquery-3.2.1.js"></script>
</head>
<body>
<h1>JIAのHOMESITE</h1>
14{{ response.text }}
 </body> 

16 </html>

当然本篇主要讨论JSONP和CORS这两种跨域技术。

一、JSONP

依据:带有 src 属性的标签不受同源策略的影响(img, script, iframe等)。

我们可以通过使用 script 标签来获取内容,但 script 中 src 获取内容后,获得到的字符串(类似于调用python中的 eval 或 exec)会被 JS 执行,所以我们可以定义一个函数,然后让服务端返回的内容外面包裹一层这个函数名,前端在访问的时候把这个函数名发送过去,并提前定义好该函数。

当然,这种方法拥有一个显著的缺点,那就是只支持GET操作。

手动实现:


服务端返回的数据

 from django.shortcuts import render,HttpResponse

 def get_data(request):
return HttpResponse('func("机密文件")')

客户端定义及获取数据

 urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^index.html/$', views.index),
url(r'^cors.html/$', views.cors),
]
 from django.shortcuts import render

 def index(request):
return render(request,"index.html")
 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="x-ua-compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Title</title>
<script src="/static/jquery-3.2.1.js"></script>
</head>
<body>
<h1>JIAのHOMESITE</h1>
<input type="button" value="获取数据" onclick="getInfo()" /> <script>
var url = 'http://127.0.0.1:8000/get_data.html/'; // 服务端路径
var $script; // 模拟使用创建的标签名 function getInfo() {
$script = document.createElement('script'); // 创建一个 script 标签
$script.setAttribute('src',url); // 将需要请求数据的地址放入 script 的 src 中
document.head.appendChild($script); // 将标签放入到 head 中
} function func(data) { // 数据返回后用来接收的函数
console.log(data);
document.head.removeChild($script); // 接收完数据后,从页面删除刚才使用的标签
}
</script>
</body>
</html>

通过JSONP自动完成 - 上面是它的原理


服务端返回的数据

 from django.shortcuts import render,HttpResponse

 def get_data(request):
# 根据后端发送过来的名字来决定返回时,数据外面套的内容
funcName = request.GET.get('callback')
return HttpResponse('%s("机密文件")'%funcName)

客户端定义及获取数据

 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="x-ua-compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Title</title>
<script src="/static/jquery-3.2.1.js"></script>
</head>
<body>
<h1>JIAのHOMESITE</h1> <script>
function func(data) {
console.log(data);
} $(function () {
var url = 'http://127.0.0.1:8000/get_data.html/';
$.ajax({
url:url,
type:'GET',
dataType:'JSONP',
jsonp:'callback',
jsonpCallback:'func'
});
})
</script>
</body>
</html>

二、CORS

随着技术的发展,现在的浏览器可以支持主动设置从而允许跨域请求,即:跨域资源共享(CORS,Cross-Origin Resource Sharing),其本质是设置响应头,使得浏览器允许跨域请求。

CORS将导致跨域访问的请求分为三种:Simple Request,Preflighted Request以及Requests with Credential。

简单请求 和 非简单请求的区别

简单请求只发送一次,直接发送数据;

非简单请求则会发送两次数据,第一次发送 opption 请求(预检),为的是查看真正的数据是否可以被接收(数据头和请求方式是否符合要求), 如果符合要求,服务端可以把内容加入到头文件中来告诉浏览器;

单请求 和 非简单请求的判断依据

条件:
1、请求方式:HEAD、GET、POST
2、请求头信息:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type 对应的值是以下三个中的任意一个
application/x-www-form-urlencoded
multipart/form-data
text/plain 注意:同时满足以上两个条件时,则是简单请求,否则为非简单请求

关于预检

- 请求方式:OPTIONS
- “预检”其实做检查,检查如果通过则允许传输数据,检查不通过则不再发送真正想要发送的消息
- 如何“预检”
=> 如果复杂请求是PUT等请求,则服务端需要设置允许某请求方式,否则“预检”不通过
Access-Control-Request-Method
=> 如果复杂请求设置了请求头,则服务端需要设置允许某请求头,否则“预检”不通过
Access-Control-Request-Headers

基于cors实现AJAX请求:

  a、支持跨域,简单请求

在使用cors的时候,客户端几乎不用修改,只需要按照普通的ajax的请求方式发送;

在服务端返回数据的时候,只要在返回的时候,加上一个响应头就可以解决这个问题了

服务器设置响应头:Access-Control-Allow-Origin = '域名' 或 '*'

*的话,代表允许所有的请求

服务端返回的数据

 from django.shortcuts import render,HttpResponse

 def get_data(request):
if request.method == 'GET':
response=HttpResponse('机密文件')
response['Access-Control-Allow-Origin'] = '*'
return response

客户端定义及获取数据

 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="x-ua-compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Title</title>
<script src="/static/jquery-3.2.1.js"></script>
</head>
<body>
<h1>JIAのHOMESITE</h1> <script>
$(function () {
var url = 'http://127.0.0.1:8000/get_data.html/';
$.ajax({
url:url,
type:'GET',
dataType:'text',
success:function (data,statusText,xmlHttpRequest) {
console.log(data);
}
})
}) </script>
</body>
</html>

  b、支持跨域,复杂请求

对于复杂请求,会先发一次预检(OPTIONS)请求,如果服务端允许,那么再发送一次正式请求(如PUT等,总之就是真正的请求)。

这个时候,我们需要在后端进行判断,如果允许用户获取数据,那么当预检(OPTIONS)过来的时候,我们需要返回允许访问的请求。

  • “预检”请求时,允许请求方式则需服务器设置响应头:Access-Control-Request-Method
  • “预检”请求时,允许请求头则需服务器设置响应头:Access-Control-Request-Headers
  • “预检”缓存时间,服务器设置响应头:Access-Control-Max-Age

服务端返回的数据

 from django.shortcuts import render, HttpResponse

 def get_data(request):

     if request.method == 'OPTIONS':
response = HttpResponse()                 // 返回的内容可以为空,主要需要返回请求头
response['Access-Control-Allow-Origin'] = '*'
response['Access-Control-Allow-Methods'] = 'PUT'  // 允许的复杂请求方式为 PUT 请求;
response['Access-Control-Allow-Headers'] = 'k1'   // 复杂请求还有一种情况就是定制请求头,这种情况下,我们在返回的响应中应该设置该响应头,代表允许发送请求头的key是什么
  return response   if request.method == 'PUT':  response = HttpResponse('机密文件')  response['Access-Control-Allow-Origin'] = '*'  return response

客户端定义及获取数据

 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="x-ua-compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Title</title>
<script src="/static/jquery-3.2.1.js"></script>
</head>
<body>
<h1>JIAのHOMESITE</h1> <script>
$(function () {
var url = 'http://127.0.0.1:8000/get_data.html/';
$.ajax({
url:url,
type:'PUT',
dataType:'text',
headers:{'k1':'v1'},
success:function (data,statusText,xmlHttpRequest) {
console.log(data); //获取响应头
console.log(xmlHttpRequest.getAllResponseHeaders());  //Content-Type: text/html; charset=utf-8
}
})
}) </script>
</body>
</html>

如果我们不想每次都经过“预检”这个环节的话,那么我们可以在服务器的响应头中增加一组:Access-Control-Max-Age的响应头,可以写成

 response['Access-Control-Allow-Headers'] = 10  // 默认单位为秒

  c、跨域获取响应头

默认获取到的所有响应头只有基本信息,如果想要获取自定义的响应头,则需要在服务器端设置Access-Control-Expose-Headers。

  d、跨域传输cookie

在跨域请求中,默认情况下,HTTP Authentication信息,Cookie头以及用户的SSL证书无论在预检请求中或是在实际请求都是不会被发送。

如果想要发送:

  • 浏览器端:XMLHttpRequest的withCredentials为true
  • 服务器端:Access-Control-Allow-Credentials为true
  • 注意:服务器端响应的 Access-Control-Allow-Origin 不能是通配符 *

服务端返回的数据

 from django.shortcuts import render, HttpResponse

 def get_data(request):
if request.method == 'OPTIONS':
response = HttpResponse()
response['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8888'
response['Access-Control-Allow-Methods'] = 'PUT'
response['Access-Control-Allow-Headers'] = 'k1'
response['Access-Control-Allow-Credentials'] = 'true' #加在了这里
return response if request.method == 'PUT':
response = HttpResponse('机密文件')
response['Access-Control-Allow-Origin'] = 'http://127.0.0.1:8888'
response['Access-Control-Allow-Credentials'] = 'true' #加在了这里
return response

客户端定义及获取数据

 <!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="x-ua-compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Title</title>
<script src="/static/jquery-3.2.1.js"></script>
</head>
<body>
<h1>JIAのHOMESITE</h1> <script>
$(function () {
var url = 'http://127.0.0.1:8000/get_data.html/';
$.ajax({
url:url,
type:'PUT',
dataType:'text',
headers:{'k1':'v1'},
xhrFields:{withCredentials:true}, //加在了这里
success:function (data,statusText,xmlHttpRequest) {
console.log(data); //获取响应头
console.log(xmlHttpRequest.getAllResponseHeaders());
}
})
}) </script>
</body>
</html>

参考博文:http://www.cnblogs.com/alwaysInMe/p/7686931.html

跨域AJAX的更多相关文章

  1. 跨域Ajax请求WebService方法

    一.允许跨域Ajax请求,更改如下配置: 在要调用的WebService上面添加特性标签: 二.以如下返回用户信息的WebService方法为例 三.在另一个网站上通过Ajax访问webService ...

  2. 使用$.getJSON实现跨域ajax请求

    jQuery中常用getJSON来调用并获取远程的JSON字符串,将其转换为JSON对象,如果成功,则执行回调函数.原型如下: jQuery.getJSON( url, [data], [callba ...

  3. 跨域Ajax请求 web.config文件配置

    在web.config文件的<system.webServer>节点下面添加如下配置代码:<!--允许跨域ajax访问--> <httpProtocol> < ...

  4. 使用JSONP进行跨域Ajax 调用

    JSONP 是啥 JSONP 全称是JSON with Padding. 当需要进行跨域Ajax 调用的时候, 需要用到JSONP 协议. 客户端 $.ajax({ url: 'http://xxx' ...

  5. 前端 - jsonp 跨域ajax

    jsonp 跨域ajax原理: 浏览器同源策略限制 如何解决同源策略限制: 方式一: 利用创建script块,在其中执行src属性为 远程url 异域 用函数(返回值) 的形式返回参数 方式二: jq ...

  6. Ajax与跨域Ajax

    Ajax 对于WEB应用程序:用户浏览器发送请求,服务器接收并处理请求,然后返回结果,往往返回就是字符串(HTML),浏览器将字符串(HTML)渲染并显示浏览器上.对于传统的Web应用,一个简单操作需 ...

  7. 跨域资源共享(CORS)--跨域ajax

    几年前,网站开发者都因为ajax的同源策略而撞了南墙.当我们惊叹于XMLHttpRequest对象跨浏览器支持所带来的巨大进步时,我们很快发现没有一个方法可以使我们用JavaScript实现请求跨域访 ...

  8. 06: AJAX全套 & jsonp跨域AJAX

    目录: 1.1 AJAX介绍 1.2 jQuery AJAX(第一种) 1.3 原生ajax(第二种) 1.4 iframe“伪”AJAX(第三种) 1.5 jsonp跨域请求 1.6 在tornad ...

  9. 跨域Ajax -- jsonp和cors

    跨域Ajax - jsonp - cors 参考博客: http://www.cnblogs.com/wupeiqi/articles/5703697.html http://www.cnblogs. ...

  10. 【HTTP header】【Access-Control-Allow-Credentials】跨域Ajax请求时是否带Cookie的设置

    1. 无关Cookie跨域Ajax请求 客户端 以 Jquery 的 ajax 为例: $.ajax({ url : 'http://remote.domain.com/corsrequest', d ...

随机推荐

  1. Bing Advanced Search Tricks You Should Know

    Bing is one of the world's most popular search engines that has gained many fans with its ease of us ...

  2. 【OpenCV】 在CentOS下搭建OpenCV开发环境

    最近开始入模式识别的坑,自然被迫上OpenCV了. 在多次尝试给VS2015扩展Windows 10 SDK无果后(不要问我为啥..VS2015开发C++的标准库全给扔到这个SDK里了,打包在VS安装 ...

  3. 常见的网络设备:集线器 hub、网桥、交换机 switch、路由器 router、网关 gateway

    Repeater 中继器 Hub 集线器 bridge 网桥 switch 交换机 router 路由器 gateway 网关 网卡 参考资料: do-you-know-the-differences ...

  4. Vue访问子组件实例或子元素

    1 尽管存在 prop 和事件,有的时候你仍可能需要在 JavaScript 里直接访问一个子组件(例如,调用子组件的方法).为了达到这个目的,你可以通过 ref 特性为这个子组件赋予一个 ID 引用 ...

  5. 【ABAP系列】SAP ABAP 工单增强

    公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[ABAP系列]SAP ABAP 工单增强   ...

  6. input复制文本

    input.value = this.$t('title') document.body.appendChild(input) input.select() input.setSelectionRan ...

  7. PowerShell 远程执行命令

    PowerShell 远程执行命令 最近在做一些自动化的测试工作,在代码实现的过程中需要远程启动/关闭一些服务或者测试机. 我首先想到的是建立一个website,通过网站对一些服务进行操作,但是这样感 ...

  8. web开发jsp页面遇到的一系列问题

    一:web总结 1.jsp页面知识点巩固 1.1字符串数字格式化转换 <%@ taglib prefix="fmt" uri="http://java.sun.co ...

  9. python常用模块---collections、time、random、os、sys、序列号模块

    collections模块 在内置数据类型(dict.list.set.tuple)的基础上,collections模块还提供了几个额外的数据类型:Counter.deque.defaultdict. ...

  10. JavaScript中函数带与不带括号的区别

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...