Django 跨域请求处理


同源策略(Same origin policy)

是一种约定安全策略,浏览器自带的安全功能

Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现

同源 

域名 , 协议  , 端口

策略

当一个浏览器的两个tab页中分别打开来 即检查是否同源,只有同源的脚本才会被执行。 如果非同源,那么在请求数据时,浏览器会在控制台中报一个异常,提示拒绝访问。

简单的跨域请求测试

场景

新建两个项目 obj1obj2 ,两个项目分别 端口号为 80068008

视图传回数据分别为 "123456" 和 "654321"

obj1.views.py

from django.shortcuts import render,HttpResponse

# Create your views here.


def index(request):
    return render(request,"index.html")



def service(request):
    return HttpResponse("123456")

obj2.views.py

from django.shortcuts import render,HttpResponse

# Create your views here.


def index(request):
    return render(request,"index.html")



def service(request):
   print("654321")
return HttpResponse("654321")

验证方式

通过 obj1中的 index 页面通过 button 按钮标签绑定 ajax事件 的 url 向 obj2 的 "http://127.0.0.1:8008/service/" 路径请求数据

$(".get_service").click(function () {
         $.ajax({
             url:"http://127.0.0.1:8008/service/",
             success:function (data) {
                 console.log(data)
             }
         })
     })

验证结果

无法取出,同源策略确实无法允许跨域的请求

通过 obj2 的后端打印确实可以看到函数被执行了,说明拦截发生在前端浏览器进行的操作

基于json 的跨域请求方式

如果所有的跨域请求拿不到,那是怎么导入外部的 js ,bootstrap ,之类的文件呢。

很明显 script 标签的  src 属性是不被拦截的

在同源策略中也只限定了脚本的执行,对于标签src 属性并没有干涉

因此基于 script 标签的 src 属性可以做些手脚

简单的测试1阶段

测试目的

查看script 标签的 src 属性请求的可行性

测试分析

便于测试我们将  http://127.0.0.1:8008/service/ 返回的数据更改一下 

obj2.views.py  

def service(request):
    print("yangtuo")
    return HttpResponse("yangtuo")

测试结果

script 标签的 src 属性请求可以实现跨域请求

同上述一样 obj2 后台执行

但是前端报错是 变量名没有被声明,最起码证明了一点数据确实被传过来了

简单的测试1阶段总结

验证 成功,scirpt 的 src 属性可以通过向目的url 请求并拿回数据放在 标签内容 里面

简单的测试2阶段

测试目的

在证实了script 标签的 src 属性请求可以实现跨域请求后,

进一步探索传递数据的可行性

测试分析 

既然拿到的数据是变量名的形式无声明报错,那解决途径两种

1. 不让传回变量名 :浏览器对标签内容的处理必然是 去除 "" 双引号,绕不过去。无解

2. 声明变量 : 那就提前声明一个变量

obj1.  index.html  在页面声明一个和请求数据相同的变量

<script>
    var yangtuo
script>

测试结果

解决报错问题

但是并没有什么卵用

对每次请求的数据设计出变量那我除非提前知道我要请求什么

我都知道了我还请求个p

延伸

既然传过来的是个变量。如果这个变量是个方法我加个"()" 不就可以执行了?

方法比单纯的数据变量可做的事情就多了去了!

简单的测试3阶段  

测试目的

利用声明方法的方式然后通过传入的参数拿到想要的数据

测试分析

obj2  views.py 

真正传递的数据通过预先一致的方法中的参数中传递

def service(request):
    print("yangtuo")
    data = "123"
    return HttpResponse(f"yangtuo({data})")

obj1   index.html

通过预先一致的方法的参数执行取出来目标数据

<script>
    function yangtuo(arg) {
        alert(arg)
    }
script>

测试结果 

拿到了预期的数据并可以进行相应的操作 ,基本实现了我们的预期要求

延伸

对于日常处理的数据在网络间传输必然是json的格式,因此基于 jsonp 的跨域请求在这一基础上诞生

简单的测试4阶段 

测试目的

测试传递更复杂的数据

测试分析

obj2  views.py 

这次尝试一下传递字典,提前用json 处理成字符串形式 

def service(request):
    print("yangtuo")
    data = {"name": "yangtuo", "age": 18}
    data = json.dumps(data)
    return HttpResponse(f"yangtuo({data})")

obj1   index.html   

查看传过来的数据类型并且使用一下数据看看

<script>
    function yangtuo(arg) {
        console.log(arg);
        console.log(typeof arg);
        var data = JSON.parse(arg);
        console.log(data);
        console.log(typeof data);

    }
script>

测试结果 

什么鬼。不应该传过来是一个字符串吗?怎么直接是对象了。

延伸 

经查阅,新版本的js 中已经自动对数据进行了还原。不再需要自己还原数据了。所以测试结果是成功的。

但是这种拿数据的方法触发是 script 标签的 src 请求,执行必须要走整个页面的刷新,实在有点蠢

我们期待的是类似于 ajax 的请求方式来拿到数据

简单的测试5阶段

测试目的

实现AJAX方式的请求方式的跨域请求 

测试分析

html 的标签的在创建的时候自动会被渲染执行,

因此可以用ajax 的方式创建 script 标签从而控制执行时间

obj1   index.html 

绑定一个点击事件,创建一个 src 属性为跨域请求的 script 标签

<script>
     $(".get_service").click(function () {
         var ele_script = $("