#######################################

"""
一、为什么会有跨域问题? 是因为浏览器的同源策略是对ajax请求进行阻拦了,但是不是所有的请求都给做跨域,像是一般的href属性,a标签什么的都不拦截。
同源策略/SOP(Same origin policy)是一种约定,由Netscape公司1995年引入浏览器,它是浏览器最核心也最基本的安全功能,
如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源。 一个源的定义
如果两个页面的协议,端口(如果有指定)和域名都相同,则两个页面具有相同的源。 举个例子:
下表给出了相对http://a.xyz.com/dir/page.html同源检测的示例: URL 结果 原因
http://a.xyz.com/dir2/other.html 成功
http://a.xyz.com/dir/inner/another.html 成功
https://a.xyz.com/secure.html 失败 不同协议 ( https和http )
http://a.xyz.com:81/dir/etc.html 失败 不同端口 ( 81和80)
http://a.opq.com/dir/other.html 失败 不同域名 ( xyz和opq)
"""

#######################################

举例说明

demo1 8002端口

# urls.py
urlpatterns = [
url(r'^abc/', views.abc),
] # views.py
def abc(request):
return HttpResponse("rion")

demo2 8000端口

# urls.py
urlpatterns = [
url(r'^xyz/', views.xyz),
]
# iews.py
def xyz(request):
return render(request, "xyz.html")

# xyz.html
<!DOCTYPE HTML>
<html>
<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>xyz</title>
</head>
<body>
<button id="b1">点我</button>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script>
$("#b1").click(function () {
$.ajax({
url: "http://127.0.0.1:8002/abc/",
type: "get",
success:function (res) {
console.log(res);
}
})
});
</script>
</body>
</html>
现在,打开使用浏览器打开http://127.0.0.1:8000/xyz/,点击页面上的 '点我' 按钮,会在console页面发现错误信息如下:
为什么报错呢?因为同源策略限制跨域发送ajax请求。

#######################################

"""

二、解决跨域问题的两种方式
JSONP
CORS """

#######################################

细心点的同学应该会发现我们的demo1项目其实已经接收到了请求并返回了响应,是浏览器对非同源请求返回的结果做了拦截。
再细心点的同学会发现,我们使用cdn方式引用的jQuery文件也是跨域的,它就可以使用。
同样是从其他的站点拿东西,script标签就可以。那我们能不能利用这一点搞点事情呢?

把xyz.html中的代码改一下:

<!DOCTYPE HTML>
<html>
<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>xyz</title>
</head>
<body>
<button id="b1">点我</button>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script src="http://127.0.0.1:8002/abc/"></script>
</body>
</html>

会报错,rion is not define ,该页面上却没有定义一个名为rion的变量。所以出错了。

那我定义一个rion变量还不行吗?

把xyz.html中的代码改一下:

<!DOCTYPE HTML>
<html>
<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>xyz</title>
</head>
<body>
<button id="b1">点我</button>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script>
var rion = 100;
</script>
<script src="http://127.0.0.1:8002/abc/"></script>
</body>
</html>

这次就不会报错了。

我定义一个变量可以,那可不可以定义一个函数呢?

<!DOCTYPE HTML>
<html>
<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>xyz</title>
</head>
<body>
<button id="b1">点我</button>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script>
function rion() {
console.log("选我不后悔!");
}
</script>
<script src="http://127.0.0.1:8002/abc/"></script>
</body>
</html>

同时把返回的响应也改一下:

def abc(request):
return HttpResponse("rion()")

我返回的 rion(),页面上拿到这个响应之后直接执行了rion函数!

那函数中可不可以传递参数呢?我们试一下!

把xyz.html中的代码改一下:

<!DOCTYPE HTML>
<html>
<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>xyz</title>
</head>
<body>
<button id="b1">点我</button>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script>
function rion(res) {
console.log(res);
}
</script>
<script src="http://127.0.0.1:8002/abc/"></script>
</body>
</html>

demo1中的视图函数:

def abc(request):
res = {"code": 0, "data": ["SNIS-561", "SNIS-517", "SNIS-539"]}
return HttpResponse("rion({})".format(json.dumps(res)))

果然传递参数也是可以的!

我们通过script标签的跨域特性来绕过同源策略拿到想要的数据了!!!

这其实就是JSONP的简单实现模式,或者说是JSONP的原型:创建一个回调函数,然后在远程服务上调用这个函数并且将JSON 数据形式作为参数传递,完成回调。

将JSON数据填充进回调函数,这就是JSONP的JSON+Padding的含义。

但是我们更多时候是希望通过事件触发数据的获取,而不是像上面一样页面一刷新就执行了,这样很不灵活。

其实这很好解决,我们可以通过javascript动态的创建script标签来实现。

<!DOCTYPE HTML>
<html>
<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>xyz</title>
</head>
<body>
<button id="b1">点我</button>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script>
function rion(res) {
console.log(res);
}
function addScriptTag(src){
var scriptEle = document.createElement("script");
$(scriptEle).attr("src", src);
$("body").append(scriptEle);
$(scriptEle).remove();
}
$("#b1").click(function () {
addScriptTag("http://127.0.0.1:8002/abc/")
})
</script>
</body>
</html>

这样当我们点击b1按钮的时候,会在页面上插入一个script标签,然后从后端获取数据。

为了实现更加灵活的调用,我们可以把客户端定义的回调函数的函数名传给服务端,服务端则会返回以该回调函数名,将获取的json数据传入这个函数完成回调。

<!DOCTYPE HTML>
<html>
<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>xyz</title>
</head>
<body>
<button id="b1">点我</button>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script>
function rion(res) {
console.log(res);
} function addScriptTag(src) {
var scriptEle = document.createElement("script");
$(scriptEle).attr("src", src);
$("body").append(scriptEle);
$(scriptEle).remove();
}
$("#b1").click(function () {
addScriptTag("http://127.0.0.1:8002/abc/?callback=rion")
});
</script>
</body>
</html>

view.py

def abc(request):
res = {"code": 0, "data": ["SNIS-561", "SNIS-517", "SNIS-539"]}
func = request.GET.get("callback")
return HttpResponse("{}({})".format(func, json.dumps(res)))

这样就能实现动态的调用了。

jQuery中有专门的方法实现jsonp。

<!DOCTYPE HTML>
<html>
<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>xyz</title>
</head>
<body>
<button id="b1">点我</button>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script>
$("#b1").click(function () {
$.getJSON("http://127.0.0.1:8002/abc/?callback=?", function (res) {
console.log(res);
})
});
</script>
</body>
</html>

要注意的是在url的后面必须要有一个callback参数,这样getJSON方法才会知道是用JSONP方式去访问服务,callback后面的那个?是jQuery内部自动生成的一个回调函数名。

但是如果我们想自己指定回调函数名,或者说服务上规定了回调函数名该怎么办呢?我们可以使用$.ajax方法来实现:

<!DOCTYPE HTML>
<html>
<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>xyz</title>
</head>
<body>
<button id="b1">点我</button>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script>
$("#b1").click(function () {
$.ajax({
url: "http://127.0.0.1:8002/abc/",
dataType: "jsonp",
jsonp: "callback",
jsonpCallback: "rion2"
})
});
function rion2(res) {
console.log(res);
}
</script>
</body>
</html>

不过我们通常都会将回调函数写在success回调中:

<!DOCTYPE HTML>
<html>
<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>xyz</title>
</head>
<body>
<button id="b1">点我</button>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script>
$("#b1").click(function () {
$.ajax({
url: "http://127.0.0.1:8002/abc/",
dataType: "jsonp",
success: function (res) {
console.log(res);
}
})
})
</script>
</body>
</html>

####################################################

"""
三、JSONP JSONP是json用来跨域的一个东西。原理是通过script标签的跨域特性来绕过同源策略。(创建一个回调函数,然后在远程服务上调用这个函数并且将json数据形式作为参数传递,完成回调)。 JSONP的缺点
jsonp有个缺陷就是只能get
而且会把请求的内容发送到url中导致安全性极低 # script标签不受同源策略的影响,手动创建一个script标签,传递URL,同时传入一个回调函数的名字
# 服务器得到名字后,返回数据时会用这个函数名来包裹住数据,客户端获取到数据之后,立即把script标签删掉 """

#######################################

 CORS解决跨域问题

CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。它允许浏览器向跨源服务器发出XMLHttpRequest请求,从而解决AJAX只能同源使用的限制。

CORS简介

CORS需要浏览器和服务器同时支持。目前基本上主流的浏览器都支持CORS。所以只要后端服务支持CORS,就能够实现跨域。

简单请求和非简单请求介绍

浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。

一个请求需要同时满足以下两大条件才属于简单请求。

(1) 请求方法是以下三种方法之一:
    HEAD
    GET
    POST (2)HTTP的头信息不超出以下几种字段:
    Accept
    Accept-Language
    Content-Language
    Last-Event-ID
    Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

简单请求的处理方式

在跨域场景下,当浏览器发送简单请求时,浏览器会自动在请求头中添加表明请求来源的 Origin 字段。

我们的后端程序只需要在返回的响应头中加上 Access-Control-Allow-Origin 字段,并且把该字段的值设置为 跨域请求的来源地址或简单的设置为 * 就可以了。

例如:我们可以在Django中间件中的process_response方法来给相应对象添加该字段。

from django.utils.deprecation import MiddlewareMixin

class CorsMiddleware(MiddlewareMixin):

    def process_response(self, request, response):
# 给响应头加上 Access-Control-Allow-Origin 字段 并简单的设置为 *
response['Access-Control-Allow-Origin'] = '*'
return response

非简单请求的处理方式

 我们开发中常用到的那些请求方法是PUT或DELETE,或者Content-Type字段的类型是application/json的都是非简单请求。

对于非简单请求,浏览器通常都会在请求之前发送一次 OPTIONS 预检 请求。该请求会像后端服务询问是否允许从当前源发送请求并且询问允许的 请求方法 和 请求头字段。

举个例子:

我们前端使用axios向后端发送PUT请求,结果:失败,

解决办法也很简单,我们可以在后端简单的给响应对象添加上 常用请求方法(PUT、DELETE)的支持就可以了

在上面Django的中间件中添加如下代码:

from django.utils.deprecation import MiddlewareMixin

class CorsMiddleware(MiddlewareMixin):

    def process_response(self, request, response):
# 给响应头加上 Access-Control-Allow-Origin 字段 并简单的设置为 *
response['Access-Control-Allow-Origin'] = '*'
if request.method == 'OPTIONS':
# 允许发送 PUT 请求
response['Access-Control-Allow-Methods'] = 'PUT, DELETE'
# 允许在请求头中携带 Content-type字段,从而支持发送json数据
response['Access-Control-Allow-Headers'] = 'Content-type'
return response

################################################

使用django-cors-headers
我们这个中间件确实能解决目前的CORS跨域问题,但是我们的土方法肯定是不够严谨的,已经有人造好轮子-- django-cors-headers 了。
我们只需要安装这个包,然后按需要配置一下就可以了。 安装
pip install django-cors-headers
注册APP
INSTALLED_APPS = [
...
'app01.apps.App01Config',
'corsheaders', # 将 corsheaders 这个APP注册
] 添加中间件
必须放在最前面,因为要先解决跨域的问题。只有允许跨域请求,后续的中间件才会正常执行。
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware', # 添加中间件
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
# 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

配置
你可以选择不限制跨域访问
CORS_ORIGIN_ALLOW_ALL = True
或者你可以选择设置允许访问的白名单
CORS_ORIGIN_ALLOW_ALL = False
CORS_ORIGIN_WHITELIST = (
# '<YOUR_DOMAIN>[:PORT]',
'127.0.0.1:8080'
)

################################################

{%csrf_token%}的作用

<form>
{%csrf_token%}
</form>
在django中我们需要在templates的form中加入{%csrf_token%}这串内容,
它的作用是当我们get表单页面时,服务器返回页面的同时也会向前端返回一串随机字符,
post提交时服务器会验证这串字符来确保用户是在服务端返回的表单页面中提交的数据,
防止有人通过例如jquery脚本向某个url不断提交数据,是一种数据提交的验证机制。

################################################

"""
四、CORS跨域
随着技术的发展,现在的浏览器可以主动支持设置从而允许跨域请求,即:跨域资源共享(CORS,Cross-Origin Resource Sharing),其本质是设置响应头,使得浏览器允许跨域请求。
2.cors:跨域资源共享
# 使用自定义的HTTP头部允许浏览器和服务器相互通信
# 1.如果是简单请求,直接设置允许访问的域名:
# 允许你的域名来获取我的数据
# response['Access-Control-Allow-Origin'] = "*"
# 2.如果是复杂请求,首先会发送options请求做预检,然后再发送真正的PUT/POST....请求
# 因此如果复杂请求是PUT等请求,则服务端需要设置允许某请求
# 如果复杂请求设置了请求头,则服务端需要设置允许某请求头
#简单请求:
# 一次请求
#非简单请求:
# 两次请求,在发送数据之前会先发一次请求用于做“预检”,
# 只有“预检”通过后才再发送一次请求用于数据传输。 """

#######################################

"""
五、JSONP和CORS的区别
JSONP:服务端不用修改,需要改前端。发jsonp请求
JSONP:只能发GET请求
CORS:前端的代码不用修改,服务端的代码需要修改。如果是简单请求的话在服务端加上一个响应头。
CORS:可以发任意请求
"""

#######################################

#######################################

#######################################

#######################################

demo1 8002端口

django框架进阶-解决跨域问题的更多相关文章

  1. django框架如何解决跨域问题

    跨域问题的由来 由于浏览器具有同源策略的限制. 限制:在发送Ajax请求时,如果当前浏览器的URL是a.com,页面中向b.com发送Ajax请求,请求可以正常访问,但数据回到浏览器时,浏览器会阻止. ...

  2. Django后端彻底解决跨域问题

    最近在接一个前后端分离的项目,后端使用的django-restframework,前端使用的Vue.后端跑起来后,发现前端在访问后端API时出了了跨域的问题. 类似如下报错: 关于跨域问题,之前这篇文 ...

  3. [django]django配合前端vue前后端联调,django服务端解决跨域(django-cors-headers)

    django内部csrf post提交数据解决 https://www.cnblogs.com/iiiiiher/articles/9164940.html 前端写了个页面,里面$.post发现403 ...

  4. django之csrf_exempt解决跨域请求的问题

    一: from django.views.decorators.csrf import csrf_exempt # 获取微信返回的code信息 @csrf_exempt def wechat_auth ...

  5. Django使用cors解决跨域问题

    1.安装Django-cors-headers模块 pip install django-cors-headers 2.配置settings.py文件 INSTALLED_APPS = [ ... ' ...

  6. gin框架中间件解决跨域问题

    http://www.niu12.com/article/45// 初始化routerrouter := gin.New() router.Use(gin.Logger()) router.Use(g ...

  7. Python之Flask和Django框架解决跨域问题,配合附加ajax和fetch等js代码

    Flask框架py解决跨域问题示例: # -*- coding: utf- -*- # by zhenghai.zhang from flask import Flask, render_templa ...

  8. 解决跨域(CORS)问题

    为什么会有跨域问题 是因为浏览器的同源策略是对ajax请求进行阻拦了,但是不是所有的请求都给做跨域,像是一般的href属性,a标签什么的都不拦截 解决跨域问题的两种方式 JSONP   推荐参考 CO ...

  9. 关于跨域介绍和djiago解决跨域问题

    什么是跨域? 跨域,指的是浏览器不能执行其他网站的脚本.它是由浏览器的同源策略造成的,是浏览器对javascript施加的安全限制. 什么是同源策略? 同源策略又分为以下两种 DOM同源策略:禁止对不 ...

随机推荐

  1. CodeForces - 748E Santa Claus and Tangerines(二分)

    题意:将n个蛋糕分给k个人,要保证每个人都有蛋糕或蛋糕块,蛋糕可切, 1.若蛋糕值为偶数,那一次可切成对等的两块. 2.若蛋糕值为奇数,则切成的两块蛋糕其中一个比另一个蛋糕值多1. 3.若蛋糕值为1, ...

  2. ubuntu下面嘚一些常用基本命令

    1)环境变量配置: 9 ~/.bashrcor ~/.bash_profile. sudo gedit ~/.bashrc 第一种sudo vim ~/.bashrc export PYTHONPAT ...

  3. XML--XML概览

    参考 https://www.cnblogs.com/fangjian0423/p/xml-namespace.html http://www.w3school.com.cn/x.asp xmlns ...

  4. blueimp,预览遮罩范围控制

    blueimg gallery github地址:https://github.com/blueimp/Gallery/blob/master/README.md 使用前提,引用css和js < ...

  5. [软件] Omnigraffle

    一个商业软件, mac下画画图, 还挺好用的. 网上可以找到可用的注册码 https://blog.csdn.net/glw0223/article/details/90736751

  6. github访问过慢解决

    为了更加愉快地使用全球最大同性交友网站上的优质资源,我们来做一些简单的本机上的调整. 通过查看下载链接,能够发现最终被指向到Amazon的服务器(http://github-cloud.s3.amaz ...

  7. SQL基础教程(第2版)第3章 聚合与排序:3-4 对查询结果进行排序

    第3章 聚合与排序:3-4 对查询结果进行排序 ● 使用ORDER BY子句对查询结果进行排序.● 在ORDER BY子句中列名的后面使用关键字ASC可以(通常省略默认)进行升序排序,使用DESC关键 ...

  8. Cracking Digital VLSI Verification Interview 第四章

    目录 Hardware Description Languages Verilog SystemVerilog 对Cracking Digital VLSI Verification Intervie ...

  9. MBProgressHUD覆盖键盘

    发送消息的时候,需要用MBProgressHUD来覆盖窗口等待发送成功,但是无论如何键盘都覆盖不上. 于是各种研究,添加到view,添加到window,都无果..想破了脑子,总觉得加到window都覆 ...

  10. Spring Cloud Hystrix熔断器隔离方案

      Hystrix组件提供了两种隔离的解决方案:线程池隔离和信号量隔离.两种隔离方式都是限制对共享资源的并发访问量,线程在就绪状态.运行状态.阻塞状态.终止状态间转变时需要由操作系统调度,占用很大的性 ...