zoukankan      html  css  js  c++  java
  • 跨域请求

    同源策略与Jsonp

    同源策略

    同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。

    同源策略,它是由Netscape提出的一个著名的安全策略。现在所有支持JavaScript 的浏览器都会使用这个策略。所谓同源是指,域名,协议,端口相同。当一个浏览器的两个tab页中分别打开来 百度和谷歌的页面当浏览器的百度tab页执行一个脚本的时候会检查这个脚本是属于哪个页面的,即检查是否同源,只有和百度同源的脚本才会被执行。如果非同源,那么在请求数据时,浏览器会在控制台中报一个异常,提示拒绝访问。

    jsonp(jsonpadding)

    之前发ajax的时候都是在自己给自己的当前的项目下发

    现在我们来实现跨域发。给别人的项目发数据,

    创建两个项目,先来测试一下

    项目一:
    <!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="http://code.jquery.com/jquery-2.1.1.min.js"></script>
    
    </head>
    <body>
    <button>ajax</button>
    {% csrf_token %}
    
    <script>
        $("button").click(function () {
            $.ajax({
                url:"http://127.0.0.1:8002/ajax_2/",  #请求项目二中的url
    
                success:function (data) {
    {#                alert(123);#}
                    alert(data)
    
                }
            })
    
        })
    </script>
    
    </body>
    </html>
    index.html
    def index(request):
    
        return render(request,"index.html")
    
    import json
    def ajax_1(request):
    
        return HttpResponse(json.dumps("ok"))
    views.py

    项目二

    <!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">
        <script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
    
    </head>
    <body>
    <button class="item_2">项目二</button>
    
    
    <script>
        $(".item_2").click(function () {
            $.ajax({
                url:"/ajax_2/",
                success:function (data) {
                    alert(123)
                    alert(data)
    
                }
            })
    
        })
    </script>
    </body>
    </html>
    index.html
    from django.shortcuts import render,HttpResponse
    
    # Create your views here.
    def index(request):
    
        return render(request,"index.html")
    import json
    
    def ajax_2(request):
        print("请求来了")
        return HttpResponse(json.dumps("项目二"))
    views.py

    访问项目一出现报错:

    但是此时的项目而中的代码已经执行:则表名浏览器对非同源请求返回的结果做了拦截。

    注意:a标签,form,img标签,引用cdn的css等也属于跨域(跨不同的域拿过来文件来使用),不是所有的请求都给做跨域

    Jsonp

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

    项目一:

    修改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>
    </head>
    <body>
    <button>ajax</button>
    {% csrf_token %}
    
    <script>
        function func(name){
            alert(name)
        }
    </script>
    <script src="http://127.0.0.1:8002/ajax_2/"></script>
    
    </body>
    </html>

    项目二:修改views.py

    def index(request):
        return render(request,"index.html")
    import json
    
    def ajax_2(request):
        print("请求来了")
    
        dict={"name":"caohcao"}
        return HttpResponse("func(%s)"%json.dumps(dict))

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

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

          一般情况下,我们希望这个script标签能够动态的调用,而不是像上面因为固定在html里面所以没等页面显示就执行了,很不灵活。我们可以通过javascript动态的创建script标签,这样我们就可以灵活调用远程服务了。

    项目一:修改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>
    </head>
    <body>
    <button onclick="f()">ajax</button>
    {% csrf_token %}
    
    <script>
        function addScriptTag(src){
           {#    创建一个script标签,让他请求一次,请求完了删除他#}
        //动态生成一个script标签,直接可以定义个函数,放在函数里面
             var script = document.createElement('script');
             script.setAttribute("type","text/javascript");
             script.src = src;
             document.body.appendChild(script);
             document.body.removeChild(script);
        }
    
    
        function func(name){
            alert("hello"+name)
        }
    #为了更加灵活,现在将你自己在客户端定义的回调函数的函数名传送给服务端,服务端则会返回以你定义的回调函数名的方法,将获取的json数据传入这个方法完成回调:
        function f(){
             addScriptTag("http://127.0.0.1:8002/ajax_2/?callbacks=func")
        }
    </script>
    
    </body>
    </html>

    项目二:修改views.py

    def ajax_2(request):
        print("请求来了")
    
        dict={"name":"caohcao"}
        print("callbacks:", request.GET.get("callbacks"))
        callbacks = request.GET.get("callbacks")   #注意要在服务端得到回调函数名的名字
    return HttpResponse("%s('%s')" % (callbacks, json.dumps(dict)))

    四、jQuery对JSONP的实现

    getJSON

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

    <button onclick="f()">sendAjax</button>
    
    <script>
    
        function f(){
              $.getJSON("http://127.0.0.1:7766/SendAjax/?callbacks=?",function(arg){
                alert("hello"+arg)
            });  匿名函数
        }
        
    </script>

    8002的views不改动。

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

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

     $.ajax

    <script>
    
        function f(){
              $.ajax({
                    url:"http://127.0.0.1:7766/SendAjax/",
                    dataType:"jsonp",    
                    jsonp: 'callbacks',   #键
              jsonpCallback:"SayHi" #函数的名字
     }); } function SayHi(arg){ alert(arg); } </script>

    8002的views不改动。

    当然,最简单的形式还是通过回调函数来处理:

    <script>
    
        function f(){
    
                $.ajax({
                   url:"http://127.0.0.1:7766/SendAjax/",
                   dataType:"jsonp",            //必须有,告诉server,这次访问要的是一个jsonp的结果。
                   jsonp: 'callbacks',          //jQuery帮助随机生成的:callbacks="wner"
                   success:function(data){
                       alert("hi "+data)
                  }
             });
    
           }
    
    </script>

      jsonp: 'callbacks'就是定义一个存放回调函数的键,jsonpCallback是前端定义好的回调函数方法名'SayHi',server端接受callback键对应值后就可以在其中填充数据打包返回了; 

    jsonpCallback参数可以不定义,jquery会自动定义一个随机名发过去,那前端就得用回调函数来处理对应数据了。利用jQuery可以很方便的实现JSONP来进行跨域访问。  

    注意 JSONP一定是GET请求

    五、应用

     // 跨域请求实例
        $(".jiangxiTV").click(function () {
    
            $.ajax({
                url:"http://www.jxntv.cn/data/jmd-jxtv2.html?callback=list&_=1454376870403",
                 dataType: 'jsonp',
                 jsonp: 'callback',
                 jsonpCallback: 'list',
                 success:function (data) {
                     console.log(data.data);   //  [{},{},{},{},{},{}]
                     week_list=data.data;
                     
                     $.each(week_list,function (i,j) {
                         console.log(i,j);  // 1 {week: "周一", list: Array(19)}
                         s="<p>"+j.week+"列表</p>";
                         $(".show_list").append(s);
    
                         $.each(j.list,function (k,v) {  // {time: "0030", name: "通宵剧场六集连播", link: "http://www.jxntv.cn/live/jxtv2.shtml"}
                              a="<p><a href='"+v.link+"'>"+v.name+"</a></p>";
                              $(".show_list").append(a);
                         })
                     })
                     
                 }
            })
    
    
        })

    CORS(应用:在django中间件中实现cors做跨域)

    CORS(中间件)

    from django.conf import settings
    class GetCore(MiddlewareMixin):

    def process_response(self,request,response):
    response["Access-Control-Allow-Origin"] = ",".join(settings.CORE_ORIGIN_LIST)
    if request.method=="OPTIONS":
    response["Access-Control-Allow-Headers"]="k1" # 允许k1请求头通过
    response["Access-Control-Allow-Methods"] = "PUT" # 允许PUT请求方式
    response['Access-Control-Allow-Credentials'] = 'true' #发送cookie,"Access-Control-Allow-Origin"不能为*

    return response

    settings.py
    CORE_ORIGIN_LIST=[
    "http://localhost:8080"
    ]

    随着技术的发展,现在的浏览器可以支持主动设置从而允许跨域请求,即:跨域资源共享(CORS,Cross-Origin Resource Sharing),其本质是设置响应头,使得浏览器允许跨域请求。

    1、简单请求和复杂请求

    条件:
        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
     
    注意:同时满足以上两个条件时,则是简单请求,否则为复杂请求

    2、简单请求和复杂请求的区别?

    简单请求:一次请求

    非简单请求:两次请求,在发送数据之前会先发第一次请求做‘预检’,只有‘预检’通过后才再发送一次请求用于数据传输。

    3、关于预检

    - 请求方式:OPTIONS
    - “预检”其实做检查,检查如果通过则允许传输数据,检查不通过则不再发送真正想要发送的消息
    - 如何“预检”
         => 如果复杂请求是PUT等请求,则服务端需要设置允许某请求,否则“预检”不通过
            Access-Control-Request-Method
         => 如果复杂请求设置了请求头,则服务端需要设置允许某请求头,否则“预检”不通过
            Access-Control-Request-Headers

    4、CORS的优缺点

    • CORS的优点:可以发任意请求
    • CORS的缺点:上是复杂请求的时候得先做个预检,再发真实的请求。发了两次请求会有性能上的损耗

    五、JSONP和CORS的区别

    JSONP:服务端不用修改,需要改前端。发jsonp请求

    JSONP:只能发GET请求

    CORS:前端的代码不用修改,服务端的代码需要修改。如果是简单请求的话在服务端加上一个响应头。

    CORS:可以发任意请求

    基于cors实现AJAX请求:

    a、支持跨域,简单请求

    服务器设置响应头:Access-Control-Allow-Origin = '域名' 或 '*'

    def service(request):
        s1=request.GET.get("v1")
        s2=request.GET.get("v2")
        s=s1+s2
        obj=HttpResponse(s)
        obj["Access-Control-Allow-Origin"]="http://localhost:63342"  #设置相应头  逗号隔开允许多个访问
        # obj["Access-Control-Allow-Origin"] = "*"    #运行所有浏览器访问,(如果想排除某个则使用中间件)
        return obj
    api
    <!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">
    
        <script src="jquery-2.1.1.js"></script>
        <title>Title</title>
        <button onclick="getDdta()">点我</button>
    
    </head>
    <body>
    <script>
        function getDdta(){
            $.ajax({
                url:"http://127.0.0.1:8000/service/?v1=caochao&v2=shenge",
                type:"GET",
                success:function (data) {
                    alert(data)
    
                }
            })
        }
    
    </script>
    
    </body>
    </html>
    html

    b、支持跨域,复杂请求

    由于复杂请求时,首先会发送“预检”(OPTIONS)请求,如果“预检”成功,则发送真实数据。

    • “预检”请求时,允许请求方式则需服务器设置响应头:Access-Control-Request-Method
    • “预检”请求时,允许请求头则需服务器设置响应头:Access-Control-Request-Headers
    • “预检”缓存时间,服务器设置响应头:Access-Control-Max-Age

    自定义请求头:

    def service(request):
        if request.method=="OPTIONS":
            obj=HttpResponse()
            obj["Access-Control-Allow-Headers"]="k1"#  允许k1请求头通过
            obj["Access-Control-Allow-Origin"] = "*"
            return obj
        else:
            s1=request.GET.get("v1")
            s2=request.GET.get("v2")
            s=s1+s2
            obj=HttpResponse(s)
            # obj["Access-Control-Allow-Origin"]="http://localhost:63342"  #设置相应头  逗号隔开允许多个访问
            obj["Access-Control-Allow-Origin"] = "*"    #运行所有浏览器访问,(如果想排除某个则使用中间件)
            return obj
    api
    <!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">
    
        <script src="jquery-2.1.1.js"></script>
        <title>Title</title>
        <button onclick="getDdta()">点我</button>
    
    </head>
    <body>
    <script>
        function getDdta(){
            $.ajax({
                url:"http://127.0.0.1:8000/service/?v1=caochao&v2=shenge",
                type:"GET",
                headers:{
                    k1:"v1"
                },
                success:function (data) {
                    alert(data)
                }
            })
        }
    </script>
    </body>
    </html>
    html

    特殊的请求方式如PUT

    def service(request):
        if request.method=="OPTIONS":
            obj=HttpResponse()
            # obj["Access-Control-Allow-Headers"]="k1"#  允许k1请求头通过
            obj["Access-Control-Allow-Methods"]="PUT"  #允许PUT请求方式
            obj["Access-Control-Allow-Origin"] = "*"
    
            return obj
        else:
            s1=request.GET.get("v1")
            s2=request.GET.get("v2")
            s=s1+s2
            obj=HttpResponse(s)
            # obj["Access-Control-Allow-Origin"]="http://localhost:63342"  #设置相应头  逗号隔开允许多个访问
            obj["Access-Control-Allow-Origin"] = "*"    #运行所有浏览器访问,(如果想排除某个则使用中间件)
            return obj
    api
    <!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">
    
        <script src="jquery-2.1.1.js"></script>
        <title>Title</title>
        <button onclick="getDdta()">点我</button>
    
    </head>
    <body>
    <script>
        function getDdta(){
            $.ajax({
                url:"http://127.0.0.1:8000/service/?v1=caochao&v2=shenge",
                type:"PUT",
    //            headers:{
    //                k1:"v1"
    //            },
                success:function (data) {
                    alert(data)
                }
            })
        }
    </script>
    </body>
    </html>
    html

    4、跨域传输cookie

    在跨域请求中,默认情况下,HTTP Authentication信息,Cookie头以及用户的SSL证书无论在预检请求中或是在实际请求都是不会被发送。

    如果想要发送:

    • 浏览器端:XMLHttpRequest的withCredentials为true
    • 服务器端:Access-Control-Allow-Credentials为true
    • 注意:服务器端响应的 Access-Control-Allow-Origin 不能是通配符 *

    待续

  • 相关阅读:
    HDU 1269 迷宫城堡 tarjan算法求强连通分量
    hrbust 1721 A + B = 0 map的应用
    关于vis标记
    poj 1703
    poj1961 kmp
    acm poj1260 dp
    矩阵链乘 hrbust 1600
    单源最短路径 hdu 2066
    最小生成树
    多维背包 hrbudt 1335 算法与追MM
  • 原文地址:https://www.cnblogs.com/caochao-/p/8831301.html
Copyright © 2011-2022 走看看