本篇主要讨论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. 组件Component详解

    [转]https://www.cnblogs.com/moqiutao/p/8328931.html

  2. day10—jQuery初步实践,关于菜单

    转行学开发,代码100天——2018-03-26 今天是本人写开发记录方面博客的第10天了,不知不觉已经涉及到jQuery框架的学习了. 第一次熬夜写前端代码还是两年前,不过中途放弃了,学的东西也日渐 ...

  3. node后台fetch请求数据-Hostname/IP doesn't match certificate's altnames解决方法

    一.问题背景 基于express框架,node后台fetch请求数据,报错Hostname/IP doesn't match certificate's altnames..... require(' ...

  4. Jenkins 官网文档翻译汇总

    Jenkins 官网地址 Jenkins 官网文档地址 用户手册 安装 Jenkins 使用 Jenkins 使用凭证 Pipeline 流水线 开始使用 Pipeline 使用 Jenkinsfil ...

  5. 《JAVA设计模式》之原型模式(Prototype)

    在阎宏博士的<JAVA与模式>一书中开头是这样描述原型(Prototype)模式的: 原型模式属于对象的创建模式.通过给出一个原型对象来指明所有创建的对象的类型,然后用复制这个原型对象的办 ...

  6. MySQL数据类型-整型

    ​ MySQL支持SQL标准整数类型integer(或INT)和SMALLINT.作为标准的扩展,MySQL还支持整数类型TINYINT.MEDIUMINT和BIGINT. 类型 所占字节 有符号最小 ...

  7. [Linux] 024 IP 地址配置和网络 yum 源

    1. IP 地址配置 (1) 使用 setup 工具 $ setup ps setup 是 RedHat 系列的功能:一般地,Debian系列没有这个功能 Xubuntu 没有这个功能 (2) 启动网 ...

  8. Linux 安装jdk+mysql+tomcat

    参考: 安装 jdk+mysql+tomcat   https://www.w3h5.com/post/65.html 安装 mysql  https://blog.csdn.net/qq_23123 ...

  9. eclipse新建maven项目出错 pom.xml报错

    问题: 1.新建项目后会提示一个这样的错 maven-compiler-plugin:3.1:compile(1 errors) maven-compiler-plugin:3.1:testCompi ...

  10. 浏览器调起摄像头(jquery+layui)

    /* 实例化camvas配置参数 config = { video:{width:Number(scale*4),height:Number(scale*3)},//视频比例4:3 canvasId: ...