如何使用CORS解决跨域问题

Posted zy740

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何使用CORS解决跨域问题相关的知识,希望对你有一定的参考价值。

如何使用CORS解决跨域问题

 

一,为什么会有跨域问题

  跨域问题的出现,是因为浏览器的同源策略对ajax请求进行阻拦了,但是并不是所有的请求都给做当做跨域,;像是一般的href属性,a标签什么的都不进行拦截

 

二,什么是同源策略

  同源策略是一种约定,它是浏览器最核心也会是最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。

  它约定请求的url地址,必须与浏览器的url地址处于同域上,也就是域名,端口,协议都相同。

  如果不同,就会报错:

已拦截跨源请求:同源策略禁止读取位于 http://127.0.0.1:8001/SendAjax/ 的远程资源。(原因:CORS 头缺少 ‘Access-Control-Allow-Origin‘)。

  实际上的结果是,请求以及被发送过去了,目标服务器也对做出了响应,只是浏览器对非同源请求的放回结果做了拦截。

三,CORS简介

  CORS,跨域资源共享,它需要浏览器和服务器同事支持,目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。

  整个CORS通信中,都是浏览器自动完成的,不需要用户的参与,对于开发者来说cors通信与同源的ajax没有差别,代码完全一样。浏览器一旦发现ajax请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有察觉。

  要实现cors通信,主要是在服务器,也就是获得数据的一方做处理。

四,cors基本的流程

  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的缺点:上是复杂请求的时候得先做一个预检,再发真实的请求,发了两次请求会有性能上的损耗。

五,实现CORS请求

  局部使用:

    简单请求(get)客户端:

技术图片
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
<button id="a" class="btn btn-success">go</button>
<script>
    $("#a").click(function () {
        $.ajax({
            url:http://127.0.0.1:8000/time/,
            type:get,
            success:function (data) {
                alert(data)
            }
            }
        )
    })
</script>
</body>
</html>
技术图片

    简单请求服务端:

技术图片
def get_time(request):
    if request.method == GET:
        ntime = time.strftime(%Y-%m-%d %X)
        obj = HttpResponse(ntime)
        obj[‘Access-Control-Allow-Origin‘] = ‘http://127.0.0.1:8001‘
        return obj
技术图片

    复杂请求(post+contentType)客户端:

技术图片
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
<button id="a" class="btn btn-success">go</button>
<script>
    $("#a").click(function () {
        $.ajax({
            url:http://127.0.0.1:8000/money/,
            type:post,
            contentType:application/json,
            data:{"name":"yjh"},
            success:function (data) {
                alert(data)
            }
            }
        )
    })
</script>
</body>
</html>
技术图片

    复杂请求服务端:

技术图片
from django.http import QueryDict
def get_money(request):
    # print(request.body)
    if not request.body:
        obj = HttpResponse(1000000000000)
    else:
        data = request.body # post请求传过来的数据以二进制的形式存放于request.body
        # 将request.body的二进制数据转化为字典形式
        dic = QueryDict(data.decode(utf-8),encoding=utf-8)
        name = dic.get(name)
        obj = HttpResponse(name)
    if request.method == OPTIONS:
        obj[Access-Control-Allow-Headers] = Content-Type
    obj[Access-Control-Allow-Origin] = http://127.0.0.1:8001
    return obj
技术图片

六:全局配置

  由于是全局配置,所以应该写在中间件中。然而,我们知道浏览器是在返回的时候出现的禁用,因此我们我们需要重写process_response方法。

  第一步:在应用文件夹根目录中,新建一个my_middleware.py文件

  第二步:在该py文件夹中写上:

技术图片
from django.utils.deprecation import MiddlewareMixin
class CorsMiddleWare(MiddlewareMixin):
    def process_response(self,request,response):
        if request.method=="OPTIONS":
            #可以加*
            response["Access-Control-Allow-Headers"]="Content-Type"
        response["Access-Control-Allow-Origin"] = "http://localhost:8080"
        return response
技术图片

  第三步:在settings.py中配置:

技术图片
MIDDLEWARE = [
    ‘app01.my_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解决跨域问题的主要内容,如果未能解决你的问题,请参考以下文章

CORS和JSONP的区别,如何解决跨域问题?

如何用CORS来解决JS中跨域的问题

Cors跨域请求问题

如何解决前端访问跨域问题

解决跨域问题(CORS)

实战,SpringBoot中如何解决CORS跨域问题~(文末送书)