一,為什么會有跨域問題
跨域問題的出現,是因為瀏覽器的同源策略對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', ]