前後端分離,解決跨域問題及django的csrf跨站請求保護 ajax 跨域 headers JavaScript ajax 跨域請求 +設定headers 實踐
1. 前後端分離解決跨域問題
解決跨域呼叫服務並設定headers 主要的解決方法需要通過伺服器端設定響應頭、正確響應options請求,正確設定 JavaScript端需要設定的headers資訊 方能實現;
關於跨域,前端會先發送OPTIONS請求,進行預檢,檢查後端是否允許前端設定的相應的請求頭,請求內容
function getCookie(name) { var cookieValue = null; if (document.cookie && document.cookie != '') {官方js解決csrfvar cookies = document.cookie.split(';'); for (var i = 0; i < cookies.length; i++) { var cookie = jQuery.trim(cookies[i]); // Does this cookie string begin with the name we want? if (cookie.substring(0, name.length + 1) == (name + '=')) { cookieValue= decodeURIComponent(cookie.substring(name.length + 1)); break; } } } return cookieValue; } var csrftoken = getCookie('csrftoken'); function csrfSafeMethod(method) { // these HTTP methods do not require CSRF protectionreturn (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); } $.ajaxSetup({ crossDomain: false, // obviates need for sameOrigin test beforeSend: function(xhr, settings) { if (!csrfSafeMethod(settings.type)) { xhr.setRequestHeader("X-CSRFToken", csrftoken); } } });
- 瀏覽器error: 添加了官方解決csrftoken的js程式碼後,報跨域錯誤
Failed to load http://127.0.0.1/course/api/signup/check_username/: Request header field X-Requested-With is not allowed by Access-Control-Allow-Headers in preflight response.
Failed to load http://127.0.0.1/course/api/signup/check_username/: Request header field X-CSRFToken is not allowed by Access-Control-Allow-Headers in preflight response.
- 後端error:
Forbidden (CSRF cookie not set.): /course/api/signup/check_username/
[26/Nov/2018 16:23:06] "POST /course/api/signup/check_username/ HTTP/1.1" 403 2857
```
- 解決方案是在django後端豁免跨域的中介軟體中新增對應的header,可以解決跨域
```
class AllowOriginMiddleware(MiddlewareMixin):
"""解決跨域"""
def process_response(self, request, response):
# 簡單請求
response['Access-Control-Allow-Origin'] = '*'
# 複雜請求,會先發送預檢請求OPTIONS
if request.method == 'OPTIONS':
response['Access-Control-Allow-Headers'] = 'Content-Type,X-Requested-With,X-CSRFToken'
response['Access-Control-Allow-Methods'] = 'POST,PUT,PATCH,DELETE'
return response
```
前後端分離解決django的csrf攔截:
方法1、簡單暴力,後端登出django的csrf中介軟體 'django.middleware.csrf.CsrfViewMiddleware',
方法2、不登出csrf中介軟體,後端通過django提供的裝飾器,為特定的檢視加上裝飾器進行csrf的豁免
from django.views.decorators.csrf import csrf_exempt,csrf_protect FBV: 直接在函式上方加裝飾器 @csrf_exempt 即可不驗證csrf CBV: 必須匯入:from django.utils.decorators import method_decorator 經測試在CBV上必須在類上加且只能給dispatch方法加 # 直接在類上面加 @method_decorator(wapper_name, name='post') #給方法post加裝飾器 @method_decorator(wapper_name, name='get') class AddClass(View) 注:其實也可以直接給View中的dispatch方法加裝飾器,這樣同樣可以實現給自己類下的所有方法加裝飾器(自己未定義dispatch方法時) @method_decorator(wapper_name, name='dispatch') class AddClass(View) 注:如果登出了csrf中介軟體,也可以通過裝飾器為個別檢視新增csrf保護
方式3:
django中使用Ajax請求的CSRF設定
將官方文件上的ajax設定照搬下來:
----js程式碼
function getCookie(name) { var cookieValue = null; if (document.cookie && document.cookie != '') { var cookies = document.cookie.split(';'); for (var i = 0; i < cookies.length; i++) { var cookie = jQuery.trim(cookies[i]); // Does this cookie string begin with the name we want? if (cookie.substring(0, name.length + 1) == (name + '=')) { cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); break; } } } return cookieValue; } var csrftoken = getCookie('csrftoken'); function csrfSafeMethod(method) { // these HTTP methods do not require CSRF protection return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); } $.ajaxSetup({ crossDomain: false, // obviates need for sameOrigin test beforeSend: function(xhr, settings) { if (!csrfSafeMethod(settings.type)) { xhr.setRequestHeader("X-CSRFToken", csrftoken); } } });
django前後端不分離解決csrf:
前後端不分離解決csrf
form表單傳送:
1. 前端模板中需要加{% csrf_token%},本質是生成一個type型別為hidden的input標籤,name=csrfmiddlewaretoken value= 隨機字串
2. form表單,post請求直接傳送
注: 如不加csrf_token標籤,form的post想成功,就智慧登出後端的csrf中介軟體了
ajax傳送:
3. 前端模板中加{% csrf_token%},
方式1:在ajax中的data中加 `'csrfmiddlewaretoken': $("[name='csrfmiddlewaretoken']").val(),`
方式2:在ajax中新增header:`headers:{“X-CSRFToken”:$("name='csrfmiddlewaretoken'").val()}`
方式3:通過js全域性設定,和上面的方式2一樣本質是從cookie中獲取 【此方法也是前後端分離,前端解決csrf的官方推薦方案】
具體見部落格:(https://www.cnblogs.com/sunxiuwen/p/9675448.html#_label13)
------------------------------------------------------------------------網友見解----------------------------------------------------------------
ajax 跨域 headers JavaScript ajax 跨域請求 +設定headers 實踐
解決跨域呼叫服務並設定headers 主要的解決方法需要通過伺服器端設定響應頭、正確響應options請求,正確設定 JavaScript端需要設定的headers資訊 方能實現。
此處手札 供後人參考~
1.第一步 服務端設定響應頭
header('Access-Control-Allow-Origin:*'); //支援全域名訪問,不安全,部署後需要固定限制為客戶端網址
header('Access-Control-Allow-Methods:POST,GET,OPTIONS,DELETE'); //支援的http 動作
header('Access-Control-Allow-Headers:x-requested-with,content-type'); //響應頭 請按照自己需求新增。
2.第二部 瞭解IE chrome 等瀏覽器 對於 跨域請求並要求設定Headers自定義引數的時候的 "預請求" 就是如果遇到 跨域並設定headers的請求,所有請求需要兩步完成!
A 第一步:傳送預請求 OPTIONS 請求。此時 伺服器端需要對於OPTIONS請求作出響應 一般使用202響應即可 不用返回任何內容資訊。(能看到這份手稿的人,本人不相信你後臺處理不了一個options請求)
B 第二步:伺服器accepted 第一步請求後 瀏覽器自動執行第二步 傳送真正的請求。此時 大多數人 會發現請求成功了,但是 有那麼幾個人會發現 請求成功了但是沒有任何資訊返回 why?因為你自定義的請求頭在伺服器響應中不存在!
檢視console輸出 會發現一個問題:
“Access-Control-Allow-Headers 列表中不存在請求標頭 XXXXXX”【IE】,
request header field xxxxxx is not allowed by Access-Control-Allow-Header【chrome】
這是因為 你的XXXX請求頭 沒有在伺服器端被允許哦~
遇到這個問題 只有通過修改伺服器端來完成,舉例:需要設定 requesttype這麼一個自定義頭,那麼 你需要在 服務端裡面 將header('Access-Control-Allow-Headers:x-requested-with,content-type,requesttype'); 同學們自行體會吧 這種語法就是根據“,”分割 自己需要設定什麼頭,必須要在 服務端請求的響應頭裡面設定好,不然客戶端永遠永遠提交不上去!
至此 JavaScript/ajax 跨域+ 修改httpheader 任務完美實現。前端 後端完全分離 大道自成!前後期分離迎來曠古的潮流
次處作為見證 2016年1月25日20:21:28
"人們都一直在抱怨 JavaScript同源策略限制了web前端的發展!然而是服務端做的不夠細緻!"
部分程式碼參考如下:程式碼只是提供了思想,具體步驟還要根據以上的文字 自行揣摩實現。以上內容看不懂 說明對於web一點也不瞭解,需要買本書看看嘍~(
客戶端程式碼:
伺服器端程式碼