CORS 请求未能成功_当遇到跨域开发时, 我们如何处理好前后端配置和请求库封装(koa/axios版)...
我們知道很多大型項(xiàng)目都或多或少的采用跨域的模式開發(fā), 以達(dá)到服務(wù)和資源的解耦和高效利用. 在大前端盛行的今天更為如此, 前端工程師可以通過nodejs或者Nginx輕松搭建起web服務(wù)器.這個(gè)時(shí)候我們只需要請(qǐng)求后端服務(wù)器的接口即可實(shí)現(xiàn)系統(tǒng)的業(yè)務(wù)功能開發(fā).這個(gè)過程中會(huì)涉及到web頁面向API服務(wù)器的跨域訪問(由于受到瀏覽器的同源策略,但是業(yè)界已有很多解決方案,接下來會(huì)介紹).通過這種開發(fā)模式使得我們真正的實(shí)現(xiàn)了前后端完全分離.
采用這種前后端單獨(dú)開發(fā)部署的模式好處有如下幾點(diǎn): 減少后端服務(wù)器的并發(fā)/負(fù)載壓力 前端項(xiàng)目和后端項(xiàng)目完全分離, 一定程度上提高了自動(dòng)化部署的靈活性, 并且代碼更易管理和維護(hù) 提高前后端開發(fā)團(tuán)隊(duì)的工作效率, 各司其職, 出現(xiàn)bug更容易定位問題 在大并發(fā)情況下可以同水平擴(kuò)展前后端服務(wù)器,利用多臺(tái)前端服務(wù)器做集群來抗住日均千萬級(jí)的pv 提高應(yīng)用容錯(cuò), 即使是API服務(wù)器掛了, 前端頁面依然能正常訪問 API服務(wù)器能同時(shí)為多個(gè)應(yīng)用平臺(tái)提供服務(wù), 大量復(fù)用接口,提升效率。(比如說微服務(wù))
雖然好處有很多, 但是為了實(shí)現(xiàn)以上的架構(gòu)模式, 我們首先要解決的就是跨域問題.
瀏覽器的同源策略
同源策略是一個(gè)重要的安全策略,它用于限制一個(gè)origin的文檔或者它加載的腳本如何能與另一個(gè)源的資源進(jìn)行交互。它能幫助阻隔惡意文檔,減少可能被攻擊的媒介。如果兩個(gè)URL的protocol(協(xié)議,比如http協(xié)議,https協(xié)議)、port (端口號(hào),如80)和 host(主機(jī),如http://developer.mozilla.org) 都相同的話,則這兩個(gè) URL 是同源。這個(gè)方案也被稱為“協(xié)議/主機(jī)/端口元組”,或者直接是 “元組”。也就是說如果不滿足以上3個(gè)條件中的任意一個(gè),則被視為跨域.
解決跨域問題的幾種方式
業(yè)界解決瀏跨域問題的方案很多, 筆者在這里粗略介紹一下: JSONP實(shí)現(xiàn)跨域 通過script標(biāo)簽和url回調(diào)來實(shí)現(xiàn)跨域, 缺點(diǎn)是只支持get請(qǐng)求 CORS CORS需要瀏覽器和后端同時(shí)支持, 后端設(shè)置Access-Control-Allow-Origin 就可以開啟 CORS postMessage 可以實(shí)現(xiàn)跨文本檔、多窗口、跨域消息傳遞(筆者之前寫可插拔式聊天機(jī)器人就是采用該方案) websocket websocket是HTML5的一個(gè)持久化的協(xié)議,它實(shí)現(xiàn)了瀏覽器與服務(wù)器的全雙工通信,也是跨域的一種解決方案 nginx反向代理 document.domain + iframe 比較傳統(tǒng)的跨域解決方案
目前作為大規(guī)模跨域開發(fā)使用最多的模式還是CORS方案,所以筆者接下來將具體介紹采用cors模式搭建前后端跨域訪問通用解決方案, 為了方便,筆者后端將采用nodejs+koa, (java/php開發(fā)類似), 前端采用axios作為請(qǐng)求庫來配合實(shí)現(xiàn)完整的cors模式.
跨域開發(fā)的后端配置(node/koa版)
要想徹底了解cors的跨域模式, 我們還是要深入實(shí)踐中來, 筆者將采用nodejs和koa中間件來實(shí)現(xiàn)cors模式的搭建.這里筆者先簡(jiǎn)單介紹一下cors:
跨域資源共享(CORS) 是一種機(jī)制,它使用額外的 HTTP 頭 來告訴瀏覽器 讓運(yùn)行在一個(gè)域上的Web應(yīng)用被準(zhǔn)許訪問來自不同源服務(wù)器上指定的資源。基本場(chǎng)景如下:
對(duì)于簡(jiǎn)單的跨域場(chǎng)景,我們只需要設(shè)置請(qǐng)求頭的Access-Control-Allow-Origin字段即可, 比如設(shè)置為*號(hào)表示允許任何域名的訪問.
這里我們使用koa2-cors這個(gè)中間件來實(shí)現(xiàn)一下, 代碼如下:
import通過這樣的配置, 我們就能輕松實(shí)現(xiàn)cors跨域, 不過現(xiàn)實(shí)開發(fā)中我們一般不會(huì)這么設(shè)置, 因?yàn)檫@樣設(shè)置意味著任何人都能訪問我們的服務(wù),安全性無法保證. 作為小型的開放服務(wù),可以采用這樣的配置加上訪問限流來實(shí)現(xiàn)免費(fèi)圖床類應(yīng)用.(開放圖床實(shí)現(xiàn)可以參考筆者之前寫的文章
徐小夕:如何使用nodeJs開發(fā)自己的圖床應(yīng)用??zhuanlan.zhihu.com)
在實(shí)際開發(fā)中, 我們會(huì)將origin的返回值設(shè)置為指定域名, 這樣就只允許該域名下的請(qǐng)求訪問, 所以正確的姿勢(shì)如下:
import通過這種方式, 我們?cè)陂_發(fā)環(huán)境中, 可以讓前端同事自由訪問我們的API接口, 提高聯(lián)調(diào)效率, 而在生產(chǎn)環(huán)境中只允許我們的WEB服務(wù)器所在域名訪問.
更進(jìn)一步
對(duì)于簡(jiǎn)單請(qǐng)求和簡(jiǎn)單的開發(fā)模式, 以上的設(shè)計(jì)就基本滿足要求了, 但是對(duì)于復(fù)雜的業(yè)務(wù)場(chǎng)景, 我們的請(qǐng)求模式往往會(huì)涉及到更多的要求, 比如說需要攜帶cookie, 用戶憑證或者自定義的請(qǐng)求頭信息等(比如典型的JWT認(rèn)證的token一般會(huì)存放到自定義的頭信息中), 此時(shí)往往會(huì)發(fā)送預(yù)檢請(qǐng)求(要求必須先使用 OPTIONS 方法發(fā)起一個(gè)預(yù)檢請(qǐng)求到服務(wù)器,以獲知服務(wù)器是否允許該實(shí)際請(qǐng)求。"預(yù)檢請(qǐng)求“的使用,可以避免跨域請(qǐng)求對(duì)服務(wù)器的用戶數(shù)據(jù)產(chǎn)生未預(yù)期的影響).
這里我們需要了解以下幾個(gè)響應(yīng)頭部的字段: Access-Control-Allow-Methods 表明服務(wù)器允許客戶端使用的請(qǐng)求方法 Access-Control-Allow-Headers 表明服務(wù)器允許請(qǐng)求中攜帶的頭部字段 Access-Control-Max-Age 表明響應(yīng)的有效時(shí)間。在有效時(shí)間內(nèi),瀏覽器無須為同一請(qǐng)求再次發(fā)起預(yù)檢請(qǐng)求 Access-Control-Expose-Headers 服務(wù)器允許瀏覽器訪問的頭信息白名單 * Access-Control-Allow-Credentials 指定了當(dāng)瀏覽器的credentials設(shè)置為true時(shí)是否允許瀏覽器讀取response的內(nèi)容
以上這5個(gè)響應(yīng)頭部字段非常重要,這也是我們解決復(fù)雜跨域場(chǎng)景的關(guān)鍵配置. 具體配置案例如下:
// 設(shè)置跨域以上是采用koa2-cors實(shí)現(xiàn)的方案, 通過設(shè)置exposeHeaders, 我們就可以在瀏覽器端拿到服務(wù)器響應(yīng)的頭部字段'WWW-Authenticate', 'Server-Authorization', 'x-show-msg', 進(jìn)而根據(jù)這些字段的值來實(shí)現(xiàn)定制化的消息機(jī)制.
需要注意的是, 我們服務(wù)器在設(shè)置credentials后,需要前端請(qǐng)求庫配置設(shè)置,比如我們需要在axios中設(shè)置withCredentials為true, 代碼如下:
import這樣我們就能成功攜帶用戶憑證并被跨域的后端服務(wù)器獲取了.以上就實(shí)現(xiàn)了我們cors模式的后端配置, 對(duì)于nodeJS為主的后端選手, 基本任務(wù)已經(jīng)完成, 對(duì)于java/PHP選手, 也可以參考類似的配置和庫來實(shí)現(xiàn). 接下來我們來實(shí)現(xiàn)前端請(qǐng)求庫的封裝.
跨域開發(fā)的前端請(qǐng)求庫封裝(axios版)
作為一名前端工程師, 沒有一個(gè)上手的請(qǐng)求庫是萬萬不行的, 目前業(yè)界比較好的輪子有axios, umi-request等, 但是后者在使用過程中有一些坑(畢竟基于fetch實(shí)現(xiàn)), 所以這里筆者將基于axios來簡(jiǎn)單實(shí)現(xiàn)一個(gè)跨域請(qǐng)求庫的封裝.方便大家集成在自己的vue或者react項(xiàng)目中. 接下來看看請(qǐng)求庫封裝的簡(jiǎn)單模型:
筆者將基于http規(guī)范的錯(cuò)誤類型進(jìn)行基本的消息系統(tǒng)設(shè)計(jì), 代碼如下:
import以上筆者結(jié)合antd的message作為消息反饋UI,利用axios的請(qǐng)求和響應(yīng)攔截來實(shí)現(xiàn)消息系統(tǒng)的設(shè)計(jì), 以上只是基本的框架, 大家可以基于以上設(shè)計(jì)進(jìn)行更加自定義的封裝.
講到這里, 大家是不是對(duì)跨域下的服務(wù)端和前端配置有了更進(jìn)一步的了解了呢?
最后
如果想學(xué)習(xí)更多H5游戲, webpack,node,gulp,css3,javascript,nodeJS,canvas數(shù)據(jù)可視化等前端知識(shí)和實(shí)戰(zhàn),歡迎在《趣談前端》專欄學(xué)習(xí)討論,共同探索前端的邊界。
更多推薦
徐小夕:如何用vue/react搭建我們的前端全棧CMS項(xiàng)目?zhuanlan.zhihu.com徐小夕:基于nodeJS從0到1實(shí)現(xiàn)一個(gè)CMS全棧項(xiàng)目(中)(含源碼)?zhuanlan.zhihu.com徐小夕:CMS全棧項(xiàng)目之Vue和React篇(下)(含源碼)?zhuanlan.zhihu.com徐小夕:從零到一教你基于vue開發(fā)一個(gè)組件庫?zhuanlan.zhihu.com徐小夕:如何從0到1教你搭建前端團(tuán)隊(duì)的組件系統(tǒng)?zhuanlan.zhihu.com徐小夕:如何優(yōu)雅的搭建nodejs開發(fā)環(huán)境及目錄設(shè)計(jì)??zhuanlan.zhihu.com徐小夕:徹底掌握redux并開發(fā)一個(gè)react實(shí)戰(zhàn)項(xiàng)目?zhuanlan.zhihu.com總結(jié)
以上是生活随笔為你收集整理的CORS 请求未能成功_当遇到跨域开发时, 我们如何处理好前后端配置和请求库封装(koa/axios版)...的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 操作系统:分享Win11几个实用小技巧,
- 下一篇: 2013Esri全球用户大会QA之Arc