跨域這個事情大家肯定都遇到過,也肯定都清楚是瀏覽器的同源策略導(dǎo)致的。
我一般遇到了就在網(wǎng)上抄一抄配置就解決了,但是關(guān)于跨域到底是怎么個原理一直沒有深究,直到遇到了一個有趣的bug:
nginx配置了反向代理后,后端服務(wù)依舊403。
圍繞著這個bug,來思考2個問題:
- 跨域是前端瀏覽器的限制,為什么需要后端來進行配置呢?
- 跨域只會發(fā)生在瀏覽器中,使用curl等工具發(fā)送請求是不會被跨域限制的,真的是這樣嗎?服務(wù)端是怎么判斷請求來源是否是瀏覽器的?
注:
解決跨域有多種方法,本文只關(guān)注CORS.
瀏覽器對于簡單請求和非簡單請求處理的流程不一樣,非簡單請求會預(yù)先使用預(yù)檢請求(OPTIONS)進行校驗,簡單請求會直接發(fā)送。這部分不是本文關(guān)注重點,不影響理解,下文都按照簡單請求舉例。
為什么需要后端配置?
想要搞清楚這個問題就要了解瀏覽器對于跨域請求的處理流程。

根據(jù)以上流程,實際上無論是否同源,后端服務(wù)器都會接到請求,所以才會對非簡單請求做預(yù)校驗的優(yōu)化。
真正判斷是否可以跨域的不是瀏覽器,是后端服務(wù)器。后端服務(wù)器會在響應(yīng)頭中增加是否允許跨域的響應(yīng)。
Access-Control-Allow-Origin瀏覽器根據(jù)響應(yīng)頭中的值來判斷是否攔截。
所以是否允許跨域要在后端服務(wù)器進行配置。
只有瀏覽器請求會觸發(fā)跨域校驗嗎?
跨域是瀏覽器的安全策略,那當(dāng)然應(yīng)該只有瀏覽器才會觸發(fā)了?一開始我也是這么覺得的,但我的后端服務(wù)在被nginx反向代理后已經(jīng)是同源了,卻還是返回了403的響應(yīng),這是怎么回事呢?
我們就要搞清楚后端服務(wù)器是如何判斷請求來源是否是瀏覽器的。
實際上是根據(jù)我們的請求頭判斷的,比如Origin,Referer等。具體的判斷邏輯是后端服務(wù)器自己做,不同的web組件之間不盡相同。
此時我把后端服務(wù)器的debug打開,發(fā)現(xiàn)后端在校驗Origin時報了不同源的異常,然后直接403返回給nginx,然后再返回到瀏覽器中。
通過curl驗證一下:
curl -w '%{http_code}' -X POST "http://ip:port/auth/login
# 返回值:
{"code":304,"msg":"用戶名或密碼錯誤","data":null}200
當(dāng)我的請求頭中不包含Origin時,可以正常響應(yīng)。
curl -w '%{http_code}' -H "Origin: http://*.*.*.*" -X POST "http://ip:port/auth/login"
# 返回值:
304
當(dāng)增加Orgin時被攔截了。
至此,問題已經(jīng)捋清楚了,解決方案有很多,我這里直接選擇修改nginx,將請求頭中的Orgin置空。
proxy_set_header origin "";
問題解決。