問題背景
瀏覽器從一個域名的網頁去請求另外一個域名的資源時,域名、端口、協議任一不一樣,都是跨域
在先後端開發過程常常會遇到跨域問題。網上也都有解決方案。html
寫這篇文章時,咱們碰到的一個場景是:要給s系統作一個擴展,前端的html、js放在s系統裏,後端須要作一個單獨的站點N.B.com。這就致使了跨域問題,大多數時候 先後端用一個CORS方案 解決跨域問題就能夠了。可是我此次有點特別。前端
前端這邊是一個get請求,按理說也沒啥,可是在請求的header裏面要添加兩個自定義的headervue
GET http://localhost:8080/api/v1/users Accept: */* Content-Type: application/json Authorization: token:21232f297a57a5a743894a0e4a801fc3 Username: admin
增長了兩個自定義字段 Authorization和Username
在請求時 我看到 network裏面出現了兩次請求記錄 第一次是一個 OPTION請求 狀態碼200第二次是個人get請求 狀態碼 401python
能夠這邊後端已經作了CORS處理。爲什麼還出現這種狀況呢。
咱們通常在項目裏解決跨域問題簡單說會採起方案有ios
2.使用JsonP。實際使用時,因爲JsonP向Server提交URL的長度限制在8000字符,超過了則被瀏覽器拒絕,所以不採用。git
對於第一種方案,後端須要作的工做是:
接口容許容許跨域請求:github
header('Access-Control-Allow-Origin:*'); //支持全域名訪問,不安全,部署後須要限制爲R.com header('Access-Control-Allow-Methods:POST,GET,OPTIONS,DELETE'); //支持的http動做 header('Access-Control-Allow-Headers:x-requested-with,content-type'); //響應頭 請按照本身需求添加。
前端發起跨域請求:就是正常的$.ajax請求便可。個人項目用的vue全家桶 用的axios 發送的請求ajax
// request攔截器 service.interceptors.request.use( config => { if (store.getters.token) { config.headers['Authorization'] =`token:${getToken()}` config.headers['Username'] =`getUsername()` } return config }, error => { // Do something with request error Promise.reject(error) } )
可是,碰到個問題,國內網站基本沒有講,就是option請求問題。json
在正式跨域的請求前,瀏覽器會根據須要,發起一個「PreFlight」(也就是Option請求),用來讓服務端返回容許的方法(如get、post),被跨域訪問的Origin(來源,或者域),還有是否須要Credentials(認證信息)
三種場景:axios
如下三項必須都成立:
application/x-www-form-urlencoded
multipart/form-data
text/plain
XHR對象對於HTTP跨域請求有三種:簡單請求、Preflighted 請求、Preflighted 認證請求。簡單請求不須要發送OPTIONS嗅探請求,但只能按發送簡單的GET、HEAD或POST請求,且不能自定義HTTP Headers。Preflighted 請求和認證請求,XHR會首先發送一個OPTIONS嗅探請求,而後XHR會根據OPTIONS請求返回的Access-Control-*等頭信息判斷是否有對指定站點的訪問權限,並最終決定是否發送實際請求信息。
那麼個人get請求呢?
原來,產生 OPTIOINS 請求的緣由是:自定義 Headers 頭信息致使的。
瀏覽器會去向 Server 端發送一個 OPTIONS 請求,看 Server 返回的 "Access-Control-Allow-Headers" 是否有自定義的 header 字段。由於我以前沒有返回自定義的字段,因此,默認是不容許的,形成了客戶端沒辦法拿到數據。
那麼這樣 的話若是後端是python的話
from corsheaders.defaults import default_headers CORS_ALLOW_HEADERS = default_headers + ( 'Authorization,Username' )
前端這邊若是用的vue全家桶 能夠這樣搞一下
module.exports = { NODE_ENV: '"development"', ENV_CONFIG: '"dev"', BASE_API: '"/proxy"' }
'/proxy': { target: 'http://jupiter.dev.grdoc.org/', changeOrigin: true, pathRewrite: { '^/proxy': '/' }, sesure:false }
開發環境這樣搞一下 應該就不算跨域了。
我是山豆 個人gitHub