Django 之 Jsonp实现跨域

发布时间 2023-08-30 18:08:52作者: f_carey

Jsonp实现跨域

1 Jsonp实现场景

jsonp是json用来跨域的一个东西。原理是通过script标签的跨域特性来绕过同源策略。

思考:这算怎么回事?

<script src="http://code.jquery.com/jquery-latest.js"></script>
  • script标签的src属性是可以直接实现跨域的,这是标签特性,所以我们可以借助它来实现跨域。

2 实例

2.1 8000

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>jsonp</title>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <script src="/static/js/jquery.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/4.6.1/js/bootstrap.min.js"></script>
</head>
<body>
<h1>dgdt</h1>
<button>ajax</button>

<script>
    function xx(arg){ //func写在下面src请求的上面,不然找不到这个func函数,我们请求的另一个网站的后端返回的数据就是这个函数名称加参数的形式  // #HttpResponse("func('chao')")
        alert(arg);
    }
</script>

<script src="http://127.0.0.1:8001/ajax"></script>
</body>
</html>

2.2 8001

from django.shortcuts import render,HttpResponse

# Create your views here.
def ajax(request):
    response = HttpResponse("xx('xxx')")
    response['content-type'] = 'application/javascript;charset=utf-8'  # 解决:来自“http://127.0.0.1:8001/ajax”的资源已被阻止,因为 MIME 类型(“text/html”)不匹配(X-Content-Type-Options: nosniff)。
    return response

2.3 小结

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

3 通过javascript动态的创建script标签

3.1 8000

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>jsonp</title>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <script src="/static/js/jquery.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/4.6.1/js/bootstrap.min.js"></script>
</head>
<body>
<h1>dgdt</h1>
<button onclick="f()">ajax</button>

<script>
    function addScriptTag(src) {
        var script = document.createElement('script');
        script.setAttribute("type", "text/javascript");
        script.src = src;
        document.body.appendChild(script);
        document.body.removeChild(script);
    }

    function xx(name) {
        console.log('hey '+name);
    }

    function f() {
        addScriptTag('http://127.0.0.1:8001/ajax')
    }
</script>

</body>
</html>

3.2 8001

from django.shortcuts import render,HttpResponse

# Create your views here.
def ajax(request):
    response = HttpResponse("xx('xxx')")
    response['content-type'] = 'application/javascript;charset=utf-8'
    return response

4 灵活部署Jsonp

为了更加灵活,现在将你自己在客户端定义的回调函数的函数名传送给服务端,服务端则会返回以你定义的回调函数名的方法,将获取的json数据传入这个方法完成回调,这样的话,后端服务器就不需要知道你的回调函数的名称是什么了,不然和上面似的,服务端必须知道你的函数名称,就不太灵活:

4.1 8000

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>jsonp</title>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <script src="/static/js/jquery.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/4.6.1/js/bootstrap.min.js"></script>
</head>
<body>
<h1>dgdt</h1>
<button onclick="f()">ajax</button>

<script>
    function addScriptTag(src) {
        var script = document.createElement('script');
        script.setAttribute("type", "text/javascript");
        script.src = src;
        document.body.appendChild(script);
        document.body.removeChild(script);
    }

    function xx(name) {
        console.log('hey '+name);
    }

    function f() {
        addScriptTag('http://127.0.0.1:8001/ajax/?callback=xx')
        // // callbacks这个名称不是固定的,和另一个网站的服务端商量好就行了,就是后端取值时的一个参数而已
    }
</script>

</body>
</html>

4.2 8001

from django.shortcuts import render, HttpResponse
import json


# Create your views here.
def ajax(request):
    dic = {"k1": "v1"}
    print("callback:", request.GET.get("callback"))
    callback = request.GET.get("callback")
    response = HttpResponse("%s('%s')" % (callback, json.dumps(dic)))
    response['content-type'] = 'application/javascript;charset=utf-8'
    return response

5 jQuery实现JSONP

jQuery框架也当然支持JSONP,可以使用$.getJSON(url,[data],[callback])方法

5.1 8000

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>jsonp</title>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <script src="/static/js/jquery.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/4.6.1/js/bootstrap.min.js"></script>
</head>
<body>
<h1>dgdt</h1>
<button onclick="f()">ajax</button>
<script>
    function f() {
        $.getJSON("http://127.0.0.1:8001/ajax/?callback=?",function (arg) {
            console.log('hey ' + arg);
        });
    }
</script>
</body>
</html>

5.2 8001

from django.shortcuts import render, HttpResponse
import json


# Create your views here.
def ajax(request):
    dic = {"k1": "v1"}
    print("callback:", request.GET.get("callback"))
    callback = request.GET.get("callback")
    response = HttpResponse("%s('%s')" % (callback, json.dumps(dic)))
    response['content-type'] = 'application/javascript;charset=utf-8'
    return response

  • 结果是一样的,要注意的是在url的后面必须添加一个callbacks(callbacks名不是固定的)参数,这样getJSON方法才会知道是用JSONP方式去访问服务,callbacks后面的那个问号是内部自动生成的一个回调函数名。

5.3 8000

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

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>jsonp</title>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <script src="/static/js/jquery.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/4.6.1/js/bootstrap.min.js"></script>
</head>
<body>
<h1>dgdt</h1>
<button onclick="f()">ajax</button>
<button onclick="f2()">ajax2</button>
<script>
    function f() {
        $.ajax({
            url: 'http://127.0.0.1:8001/ajax/?callback=hey',
            dataType: 'jsonp',
            jsonp: 'callback',  // jsonp: 'callbacks'就是定义一个存放回调函数的键,jsonpCallback是前端定义好的回调函数方法名'SayHi',server端接受callback键对应值后就可以在其中填充数据打包返回了; 
            jsonpCallback: 'hey',  // jsonpCallback参数可以不定义,jquery会自动定义一个随机名发过去,那前端就得用回调函数来处理对应数据了。利用jQuery可以很方便的实现JSONP来进行跨域访问。
            type: 'get',
        })
    }

    function hey(arg) {
        console.log(arg);
    }

    function f2() {
        $.ajax({
            url: 'http://127.0.0.1:8001/ajax/?callback=hey',
            dataType: 'jsonp',
            jsonp: 'callback',
            type: 'get',
            success: function (data) {
                console.log('hey ' + data);
            }
        })
    }
</script>
</body>
</html>
  • 注意: JSONP一定是GET请求