浏览器的同源策略,及如可跨域

1、同源策略

  所谓同源是指,域名,协议,端口相同。当一个浏览器的打开一个页面时中,页面请求非同源的URL时,请求能正常响应,但是浏览器会判断请求的URL和本页面的URL是否同源,

如果非同源的话,就会在本页面返回一个错误,并且得不到返回的数据。

2、解决跨域的方法

2.1、CORS通信实现跨域请求

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

  只要同时满足以下两大条件,就属于简单请求。 

(1) 请求方法是以下三种方法之一:(也就是说如果你的请求方法是什么put、delete等肯定是非简单请求)
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,也就是说,如果你发送的application/json格式的数据,那么肯定是非简单请求,vue的axios默认的请求体信息格式是json的,ajax默认是urlencoded的。

对于简单的请求只需要我么请求URL的响应函数views里面配置响应头Access-Control-Allow-Origin

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

    <script>
        function func(name) {
            alert(name)

        }
    </script>
    <script src="http://127.0.0.1:8001/base/"></script>
</head>
<body>

<form>
    <input type="button" id="id_button" value="button">

</form>
<script src="/static/jquery-2.1.4.min.js"> </script>
<script>
    $("#id_button").click(function () {
        $.ajax({
            url:'http://127.0.0.1:8001/base/',
            type:'GET',
            success:function () {
                alert('1111')

            }
        })

    })
</script>
</body>
</html>
index.html
from django.shortcuts import render,HttpResponse

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

def base(request):
    response = HttpResponse('func("wuzhiib")')
    response['Access-Control-Allow-Origin'] ='http://127.0.0.1:8000'
   # 在我们请求的URL的views里面设置,’*‘表示允许所有URL通过
    return response
views.py

浏览器对简单请求和复杂请求的处理是不一样的

* 简单请求和非简单请求的区别?

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

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

如果在Ajax请求中加入ContentType就会使普通的请求变成复杂的请求。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

    <script>
        function func(name) {
            alert(name)

        }
    </script>
    <script src="http://127.0.0.1:8001/base/"></script>
</head>
<body>

<form>
    <input type="button" id="id_button" value="button">

</form>
<script src="/static/jquery-2.1.4.min.js"> </script>
<script>
    $("#id_button").click(function () {
        $.ajax({
            url:'http://127.0.0.1:8001/base/',
            type:'GET',
            contentType:'application/json',
            success:function () {
                alert('1111')

            }
        })

    })
</script>
</body>
</html>
index.html

对对于复杂的请求要在对应的头里面做设置,Contenttype只需要在响应头里面设置X-Content-Type-Options

from django.shortcuts import render,HttpResponse
from django.http import JsonResponse

# Create your views here.


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

def base(request):
    response = HttpResponse('func("wuzhiib")')
    response['Access-Control-Allow-Origin'] ='http://127.0.0.1:8000'
    response['Access-Control-Allow-Headers'] = "content-type" #复杂请求ContentType的跨域方法
    return response
views.py

3、JsonP实现跨域

  非同源的URL不能阻止src属性的请求,也就是说通过src属性我们能跨域请求数据

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

    <script>
        function func(name) {
            alert(name)
        }
    </script>
    <!--利用script标签来实现跨域请求,返回的是func(''wuzhibin),相当于实现上面func函数的调用-->
    <script src="http://127.0.0.1:8001/base/"></script>
</head>
<body>

<form>
    <input type="button" id="id_button" value="button">

</form>
<script src="/static/jquery-2.1.4.min.js"> </script>
<script>
    $("#id_button").click(function () {
        $.ajax({
            url:'http://127.0.0.1:8001/base/',
            type:'GET',
            contentType:'application/json',
            success:function () {
                alert('1111')

            }
        })

    })
</script>
</body>
</html>
index.html
from django.shortcuts import render,HttpResponse


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

def base(request):
    response = HttpResponse('func("wuzhiib")')
    response['Access-Control-Allow-Origin'] ='http://127.0.0.1:8000'
    response['Access-Control-Allow-Headers'] = "content-type" #复杂请求ContentType的跨域方法
    #浏览器报错因为 MIME 类型(“text/html”)不匹配(X-Content-Type-Options: nosniff)
    response['X-Content-Type-Options'] ="application/json" 
    return response
views.py

注意如果如果不配之响应头的X-Content-Type-Options属性,浏览器会报一个错误

浏览器的同源策略,及如可跨域

上面就是Jsonp实现的原理,这个只是哟个简单的例子,一般我们都需要能够动态的实现标签的创建

动态创建script标签

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<script src="/static/jquery-2.1.4.min.js"> </script>
<button onclick="f()">sendAjax</button>
<!--动态创建标签Script-->
<script>
    function addScriptTag(src){
         var script = document.createElement('script');
         script.setAttribute("type","text/javascript");
         script.src = src;
         document.head.appendChild(script);
         // document.body.removeChild(script);
    }
    // 接受返回数据的回调函数
    function func(name){
        alert("hello"+name)
    }
    function f(){
         addScriptTag("http://127.0.0.1:8001/base/")
    }
</script>
</body>
</html>
index.Html

views.py与上面一直

from django.shortcuts import render,HttpResponse


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

def base(request):
    response = HttpResponse('func("wuzhiib")')
    response['Access-Control-Allow-Origin'] ='http://127.0.0.1:8000'
    response['Access-Control-Allow-Headers'] = "content-type" #复杂请求ContentType的跨域方法
    #浏览器报错因为 MIME 类型(“text/html”)不匹配(X-Content-Type-Options: nosniff)
    response['X-Content-Type-Options'] ="application/json"
    return response
views.py

上面的例子中,我们在前端定义函数的时,另一个域明显是不知道我们我们前端定义的是func的,所以我们需要将函数名传给跨域的views函数动态生成返回函数名

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<script src="/static/jquery-2.1.4.min.js"> </script>
<button onclick="f()">sendAjax</button>
<!--动态创建标签Script-->
<script>
    function addScriptTag(src){
         var script = document.createElement('script');
         script.setAttribute("type","text/javascript");
         script.src = src;
         document.head.appendChild(script);
         // document.body.removeChild(script);
    }
    // 接受返回数据的回调函数
    function func(name){
        var name=name
        alert("hello"+name)
    }
    function f(){
         addScriptTag("http://127.0.0.1:8001/base/?callbacks=func")
    }
</script>
</body>
</html>
index.html
from django.shortcuts import render,HttpResponse


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

def base(request):
    # 返回给跨域请求的数据
    data = 'wuzhibin'
    #获取跨域请求的函数名
    callback = request.GET.get('callbacks')
    print(callback)

    response = HttpResponse("%s('%s')"%(callback,data))
    response['Access-Control-Allow-Origin'] ='http://127.0.0.1:8000'
    response['Access-Control-Allow-Headers'] = "content-type" #复杂请求ContentType的跨域方法
    #浏览器报错因为 MIME 类型(“text/html”)不匹配(X-Content-Type-Options: nosniff)
    response['X-Content-Type-Options'] ="application/json"
    return response
view.py
Ajax中使用Jsonp

在实际的用处中,在Ajax中使用跨站请求数据的场景比较多一些。而不是单独生产动态生成一个Script标签去请求数据

from django.shortcuts import render,HttpResponse
from django.http import JsonResponse

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

def base(request):
    import json
    # 返回给跨域请求的数据,一般都是字典的格式
    data = {
        'key1':'value1',
        'key2':'value2',
        'k3':'value3',
        'k4':'value4',
    }
    #等到跨域的方法名
    callbacks = request.GET.get("callbacks")

    response =HttpResponse("%s('%s')"%(callbacks,json.dumps(data)))
    response['Access-Control-Allow-Origin'] ='http://127.0.0.1:8000'
    response['Access-Control-Allow-Headers'] = "content-type" #复杂请求ContentType的跨域方法
    #浏览器报错因为 MIME 类型(“text/html”)不匹配(X-Content-Type-Options: nosniff)
    response['X-Content-Type-Options'] ="application/json"
    return response
views.py
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<script src="/static/jquery-2.1.4.min.js"> </script>
<button onclick="f()">sendAjax</button>
<!--动态创建标签Script-->

<script>
function f(){
      $.ajax({  //大家会发现我的type请求方法没写,默认是get请求
            url:"http://127.0.0.1:8001/base/",
            dataType:"jsonp",
            jsonp: 'callbacks',
            jsonpCallback:"SayHi"
       });
   }
function SayHi(arg){
            // 将字符串转发为字典的格式
           var data = JSON.parse(arg);
            alert(data.key1);  //k1是后端返回的数据中的键值对的键
        }
</script>
</body>
</html>
index.html

 也能通过Ajax的success函数获取跨域的数据,这种方式比较简单些

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<script src="/static/jquery-2.1.4.min.js"> </script>
<button onclick="f()">sendAjax</button>
<!--动态创建标签Script-->

<script>
function f(){
      $.ajax({  //大家会发现我的type请求方法没写,默认是get请求
            url:"http://127.0.0.1:8001/base/",
            dataType:"jsonp",
            jsonp: 'callbacks',
            jsonpCallback:"SayHi",
            success:function (rag) {
                var data = JSON.parse(rag)
                alert(data.key1)
            }
       });
   }
</script>
</body>
</html>
index.html

views.py函数和上面保持一致

相关推荐