CORS實(shí)現(xiàn)跨域的過程

當(dāng)加上 CORS 之后,從發(fā)起到請求正式成功一般會經(jīng)歷以下過程:

簡單請求(以 GET、POST 等簡單方法且無特殊請求頭的請求為例)

  1. 發(fā)起請求:客戶端(通常是瀏覽器)向跨域的服務(wù)器發(fā)送請求,例如使用 fetchXMLHttpRequest 等 API。請求頭中會包含 Origin 字段,它表示請求發(fā)起的源,包括協(xié)議、域名和端口號。
  2. 服務(wù)器接收請求:服務(wù)器接收到請求后,會檢查 Origin 字段。然后根據(jù)自身的 CORS 配置,判斷該源是否被允許訪問。
  3. 服務(wù)器響應(yīng):如果 Origin 是允許的,服務(wù)器會在響應(yīng)頭中添加 Access - Control - Allow - Origin 字段,其值為允許的源(可以是具體的源,也可能是 * 表示允許所有源)。同時(shí),可能還會添加其他相關(guān)的 CORS 響應(yīng)頭,如 Access - Control - Allow - Credentials(如果涉及到跨域攜帶憑證)等。然后將響應(yīng)數(shù)據(jù)發(fā)送給客戶端。
  4. 客戶端處理響應(yīng):瀏覽器接收到響應(yīng)后,檢查 Access - Control - Allow - Origin 等 CORS 相關(guān)頭信息。如果這些頭信息表明請求是被允許的,瀏覽器就會正常處理響應(yīng)數(shù)據(jù),將其傳遞給前端應(yīng)用程序進(jìn)行進(jìn)一步處理和展示。

復(fù)雜請求(如 PUT、DELETE 方法或帶有自定義請求頭的請求)

  1. 發(fā)起預(yù)檢請求(OPTIONS) :客戶端首先會發(fā)送一個(gè)預(yù)檢請求,使用 OPTIONS 方法。請求頭中包含 Origin 字段,同時(shí)還會有 Access - Control - Request - Method 字段,用于告知服務(wù)器實(shí)際請求將使用的方法(如 PUTDELETE 等),以及 Access - Control - Request - Headers 字段,列出實(shí)際請求中會包含的自定義請求頭。

  2. 服務(wù)器接收預(yù)檢請求:服務(wù)器接收到預(yù)檢請求后,根據(jù)自身的 CORS 配置,檢查 Origin 以及 Access - Control - Request - MethodAccess - Control - Request - Headers 字段,判斷是否允許該請求。

  3. 服務(wù)器響應(yīng)預(yù)檢請求:如果允許,服務(wù)器會在響應(yīng)頭中添加 Access - Control - Allow - Origin 字段,指定允許的源。同時(shí),還會添加 Access - Control - Allow - Methods 字段,列出允許的請求方法;Access - Control - Allow - Headers 字段,列出允許的請求頭。此外,還可能有 Access - Control - Max - Age 字段,指定預(yù)檢請求的結(jié)果可以被緩存的時(shí)長(以秒為單位)。

  4. 客戶端處理預(yù)檢響應(yīng):瀏覽器接收到預(yù)檢響應(yīng)后,檢查 CORS 相關(guān)頭信息。如果預(yù)檢請求被允許,瀏覽器會繼續(xù)發(fā)起實(shí)際的請求。

  5. 發(fā)起實(shí)際請求:客戶端按照正常流程發(fā)起實(shí)際的跨域請求,方法和請求頭與預(yù)檢請求中聲明的一致。

  6. 服務(wù)器接收和響應(yīng)實(shí)際請求:服務(wù)器接收實(shí)際請求,處理并返回響應(yīng),響應(yīng)頭中同樣會包含 Access - Control - Allow - Origin 等 CORS 相關(guān)頭信息,客戶端根據(jù)這些頭信息來決定是否處理響應(yīng)數(shù)據(jù)。

在整個(gè)過程中,CORS 機(jī)制通過請求頭和響應(yīng)頭的交互,讓服務(wù)器能夠明確告知瀏覽器哪些跨域請求是被允許的,從而實(shí)現(xiàn)了在遵循同源策略的基礎(chǔ)上,安全地進(jìn)行跨域資源訪問。

怎么用CORS實(shí)現(xiàn)跨域

以下是使用 CORS(跨域資源共享) 實(shí)現(xiàn)跨域的完整方案,涵蓋服務(wù)端配置、前端請求細(xì)節(jié)及常見問題處理:


一、CORS 核心機(jī)制

CORS 通過服務(wù)端設(shè)置 HTTP 響應(yīng)頭,告知瀏覽器允許特定頁面的跨域請求。瀏覽器根據(jù)響應(yīng)頭決定是否放行跨域請求。


二、服務(wù)端配置

1. 基礎(chǔ)響應(yīng)頭設(shè)置

在服務(wù)端響應(yīng)中添加以下頭信息(以 Node.js 為例):

// Express 中間件示例
app.use((req, res, next) => {
  // 允許的源(根據(jù)需求替換為具體域名)
  res.setHeader('Access-Control-Allow-Origin', 'https://your-frontend.com');
  
  // 允許的請求方法
  res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
  
  // 允許的請求頭(需明確列出)
  res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
  
  // 允許攜帶 Cookie(如需)
  res.setHeader('Access-Control-Allow-Credentials', 'true');
  
  // 預(yù)檢請求緩存時(shí)間(秒)
  res.setHeader('Access-Control-Max-Age', '86400');
  
  next();
});

2. 處理預(yù)檢請求(OPTIONS)

對于非簡單請求(如 Content-Type: application/json),瀏覽器會先發(fā)送 OPTIONS 預(yù)檢請求:

// 單獨(dú)處理 OPTIONS 請求
app.options('*', (req, res) => {
  res.sendStatus(200);
});

三、前端請求配置

1. 簡單請求(Simple Request)

滿足以下條件時(shí),瀏覽器直接發(fā)送請求:

  • 方法為 GET/POST/HEAD
  • 頭信息僅含AcceptAccept-LanguageContent-LanguageContent-Type(值限于 text/plainmultipart/form-dataapplication/x-www-form-urlencoded

示例

fetch('https://api.example.com/data')
  .then(response => response.json())
  .then(data => console.log(data));

2. 復(fù)雜請求(需預(yù)檢)

對于其他請求(如 PUT、自定義頭、Content-Type: application/json):

fetch('https://api.example.com/data', {
  method: 'PUT',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer xxx'
  },
  body: JSON.stringify({ key: 'value' })
});

3. 攜帶 Cookie

需前后端協(xié)同設(shè)置:

// 前端請求添加 credentials
fetch('https://api.example.com/data', {
  credentials: 'include' // 或 'same-origin'
});

// 服務(wù)端設(shè)置
res.setHeader('Access-Control-Allow-Credentials', 'true');
// 注意:此時(shí) Access-Control-Allow-Origin 不能為 *

五、常見問題與調(diào)試

1. 錯(cuò)誤排查

  • 預(yù)檢失敗:檢查 OPTIONS 響應(yīng)頭是否完整
  • 頭信息不匹配:確保 Access-Control-Allow-Headers 包含所有請求頭
  • Cookie 未攜帶:檢查前端 credentials 設(shè)置和服務(wù)端 Allow-Credentials

2. 瀏覽器控制臺警告

  • No 'Access-Control-Allow-Origin' header:服務(wù)端未正確設(shè)置允許的源
  • Credentials not supported:服務(wù)端使用 Access-Control-Allow-Origin: * 但前端嘗試攜帶 Cookie

3. 工具驗(yàn)證

使用 curl 檢查響應(yīng)頭:

curl -I -X OPTIONS https://api.example.com/data
# 檢查返回的 CORS 頭信息

六、安全最佳實(shí)踐

  1. 限制允許的源:避免使用 Access-Control-Allow-Origin: *,應(yīng)指定具體域名
  2. 縮小方法范圍:按需設(shè)置 Access-Control-Allow-Methods
  3. 驗(yàn)證請求頭:明確列出允許的請求頭(避免使用 *
  4. 限制緩存時(shí)間:合理設(shè)置 Access-Control-Max-Age(避免過長)

通過以上配置,CORS 可安全高效地實(shí)現(xiàn)跨域請求,是現(xiàn)代 Web 應(yīng)用的首選方案。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,443評論 6 532
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,530評論 3 416
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,407評論 0 375
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,981評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,759評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,204評論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,263評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,415評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,955評論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,782評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,983評論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,528評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,222評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,650評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,892評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,675評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,967評論 2 374

推薦閱讀更多精彩內(nèi)容

  • 我好像給了友誼一個(gè)錯(cuò)誤的定義,我總是因?yàn)槲业暮门笥延辛诵屡笥讯桓吲d。 我的好朋友有了新的圈子新的...
    程cccccccyt啊閱讀 392評論 0 0
  • 昨天不是一班的一個(gè)男生和我們班的一個(gè)女生談戀愛嗎,今天早上那個(gè)男生被他們班的老師叫進(jìn)去辦公室了 ,他們老師對他說,...
    開心每一天Wjr閱讀 180評論 0 1
  • 和女生溝通時(shí)的幾副牌: 示弱感情牌、理解共情牌、呵護(hù)關(guān)心牌、贊美夸獎(jiǎng)牌。 一、尤其要不吝贊美(尤其是女生)贊美什么...
    煮雪烹茶惠閱讀 163評論 1 1
  • 這天我們班的一個(gè)小女生帶來了“醫(yī)藥箱”,她一拿過來我們班的小朋友們就非常感興趣,因?yàn)槭切聛淼牟牧希援?dāng)她...
    XK_4a6b閱讀 215評論 0 0
  • 音樂里的故事6 大海 從那遙遠(yuǎn)海邊 慢慢消失的你 本來模糊的臉 竟然漸漸清晰 想要說些什么 又不知從何說起 只有...
    彭求實(shí)閱讀 309評論 0 2