本篇主要讨论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. HDU6415 Rikka with Nash Equilibrium

    HDU6415 Rikka with Nash Equilibrium 找规律 + 大数 由于规律会被取模破坏,所以用了java 找出规律的思路是: 对于一个n*m的矩阵构造,我先考虑n*1的构造,很 ...

  2. P1970花匠

    传送 首先,这道题据说是一个dp 其次,贪心就能做 我们先来看好想好写的贪心 按照题目来,所有偶数点要么都是凸的,要么都是凹的,不能有凸有凹.我们把每株花的高度都在平面直角坐标系中点出来,再连线.这样 ...

  3. STM32 I2C 难点---这个不错,留着慢慢研究

    来自:http://bbs.ednchina.com/BLOG_ARTICLE_2154168.HTM I2C 总线在所有嵌入式系统中用得极广, 是一个工业级别的总线, 但由于STM32 是一个32位 ...

  4. day32—CSS多列布局学习

    转行学开发,代码100天——2018-04-17 关于多列布局,前期已经梳理过,今天的培训课程学习中再次提及,趁此也做个总结和检验. 多列布局的介绍参考: day08—css布局解决方案之多列布局   ...

  5. Git是目前世界上最先进的分布式版本控制系统(没有之一)。

    http://zhidao.baidu.com/link?url=NSYPiSvtGTMoqMA9vt68FRRF8WbfYVmwWeMh47_2lkp0K3jFMl--1Co1tg1R4VshTQV ...

  6. Vagrant 手册之 Multi-machine 多机器

    原文地址 Vagrant 可以在一个 Vagrantfile 中定义并控制多个虚拟机.这就是"multi-machine"环境. 这些机器可以协同工作或互相关联.multi-mac ...

  7. JS对象—对象总结(创建、属性、方法)

    1.创建对象Object 1.1 字面量的方式创建 1.2  new Object() 1.3 构造函数创建 1.4 工厂模式 1.5 Object.create()  ES5新增方法 Object. ...

  8. JavaScript.convertArray

    function convertArray(nodeList){     var arr = []     if(Array.prototype.slice){         arr = [].sl ...

  9. MySQL-第一篇认识MySQL

    1.什么是mysql mysql是一种关系型数据库,是瑞典MySQL AB 公司开发,目前属于 Oracle 旗下产品. 2.mysql的安装 下载mysql-installer-community- ...

  10. 提交代码到github

    1. 下载git 点击download下载即可.下载地址:https://gitforwindows.org/ 2. 注册github github地址:https://github.com/ 一定要 ...