前端跨域問題--解析與實戰

引言

在現代網絡應用中,跨域問題是一個常見的挑戰。由于瀏覽器的同源策略,限制了從不同源(域名、協議或端口)進行資源共享,這就造成了跨域訪問的限制。跨域資源共享(CORS)是一種技術,它允許網頁上的腳本能夠與不同源的服務器交互,是解決這一問題的關鍵技術。

跨域資源共享(CORS)簡述

CORS 是一種網絡安全協議,它定義了在服務器和客戶端之間如何安全地實現跨源訪問。通過在服務器端設置特定的HTTP頭部,CORS 允許開發者指定哪些外部資源是可以被網頁訪問的,大幅度提升了網絡應用的互操作性和安全性。

CORS 概念解析

什么是同源策略?

同源策略是瀏覽器的一項安全功能,它限制了一個源中的文檔或腳本如何與另一個源的資源進行交互。這是一個用于隔離潛在惡意文件的重要安全措施,不允許不同源之間的讀取數據。

CORS 是如何工作的?

CORS 通過在服務器端返回一系列 CORS 響應頭來工作,如 Access-Control-Allow-Origin,這些頭信息指示瀏覽器允許哪些網站通過腳本訪問該服務器的資源。如果 CORS 頭信息缺失或值不正確,瀏覽器將阻止任何跨源請求。

實現 CORS 的常用方法

使用 JSONP 解決跨域問題

JSONP(JSON with Padding)是一種早期用于繞過同源策略的技術,它通過動態添加?<script>?標簽來請求一個帶有回調函數的URL,從而實現跨域請求。這種方法只支持GET請求。

實現 CORS:基本概念和步驟

CORS 的實現涉及在服務器端設置適當的HTTP頭。例如,Access-Control-Allow-Origin 可以被設置為特定的域名或星號(*),表示允許所有域名的跨域請求。

通過 Express.js 設置 CORS

基本 CORS 設置

在 Express.js 中,可以使用?cors?中間件來簡化 CORS 的配置。例如,可以全局配置應用以接受來自某個特定源的請求:

const cors = require('cors');
app.use(cors({origin: 'http://example.com'
}));

高級 CORS 設置(攜帶憑證、允許多種 HTTP 方法等)

對于需要更復雜的 CORS 配置,如支持憑證或多種HTTP方法,可以詳細配置?cors?中間件的選項:

app.use(cors({origin: 'http://example.com',methods: ['GET', 'POST'],credentials: true
}));

Node.js 項目實戰演練

基礎文件和目錄結構

首先,創建以下目錄和文件結構:

cross-origin-project/
│
├── public/
│   └── index.html
│
├── serverA.js
└── serverB.js
文件內容
  1. public/index.html - 這是服務 A 將托管的靜態 HTML 文件,用于發起跨域請求。
  2. serverA.js - 這個文件包含了服務 A 的代碼,用于托管靜態頁面。
  3. serverB.js - 這個文件包含了服務 B 的代碼,用于提供 API 并處理 CORS。

服務 A:提供靜態 HTML 頁面

服務 A 托管靜態 HTML 頁面,允許用戶通過按鈕觸發跨域請求。服務運行在端口 3001。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Cross-Origin Example</title>
<script>
async function fetchData() {try {const response = await fetch('http://localhost:3002/data', {method: 'GET',credentials: 'include', // 啟用憑證headers: {'X-Custom-Header': 'value' // 添加不被允許的頭部}});const data = await response.json();document.getElementById('data').textContent = JSON.stringify(data);} catch (error) {console.error('Error:', error);}
}
</script>
</head>
<body>
<h1>Cross-Origin Resource Sharing (CORS) Test</h1>
<button onclick="fetchData()">Fetch Data</button>
<p id="data"></p>
</body>
</html>

將以下 JavaScript 代碼保存到 serverA.js 文件中。這段代碼配置了一個 Express.js 服務器來托管 public 目錄下的靜態文件。

const express = require('express');
const app = express();// 提供靜態文件
app.use(express.static('public'));app.listen(3001, () => {console.log('Server A running on http://localhost:3001');
});

服務 B:提供 API 數據

將以下 JavaScript 代碼保存到 serverB.js 文件中。這段代碼創建了另一個 Express.js 服務器,它提供一個 API 端點并配置了 CORS 以允許來自服務 A 的跨域請求。

Node.js 配置(服務 B):

const express = require('express');
const cors = require('cors');
const app = express();// 配置 CORS 策略
app.use(cors({origin: 'http://localhost:3001', // 允許來自 3001 端口的跨域請求methods: ['GET'],credentials: true, // 允許跨域請求包含憑證信息allowedHeaders: ['Content-Type', 'X-Custom-Header'] // 明確允許自定義頭部
}));app.get('/data', (req, res) => {const allowedOrigins = ['http://localhost:3001'];const origin = req.headers.origin;if (allowedOrigins.includes(origin)) {res.json({ message: 'Successfully fetched cross-origin data from server B.' });} else {res.status(403).send('Access denied');}
});app.listen(3002, () => {console.log('Server B running on http://localhost:3002');
});

如何運行項目

  1. 打開命令行界面,并導航到 cross-origin-project 文件夾。
  2. 運行 npm init -y 來初始化 Node.js 項目,并通過 npm install express cors 安裝必要的依賴。
  3. 在兩個不同的命令行窗口中,分別啟動服務 A 和服務 B:
    • 運行 node serverA.js 啟動服務 A。
    • 運行 node serverB.js 啟動服務 B。

訪問 http://localhost:3001 在瀏覽器中查看 HTML 頁面,并嘗試發起跨域請求。此時應該能看到成功信息打印成功。

跨域原因列舉

CORS(跨域資源共享)設置可能因為多種原因而失敗,導致跨域請求無法成功。這些原因包括配置錯誤、環境限制或者瀏覽器的安全策略。下面是一些常見的原因導致跨域設置不成功:

1. 錯誤的源設置

如果 CORS 策略中設置的 Access-Control-Allow-Origin 頭不正確,如不匹配請求的源(origin),跨域請求將被拒絕。例如,如果服務器只允許來自 http://localhost:3001 的請求,但請求實際來自 http://127.0.0.1:3001(盡管這兩個地址指向同一個位置,但對 CORS 來說它們是不同的源)。

2. 忽略發送憑證

如果在 AJAX 請求中設置了 withCredentials = true,但服務器端的 CORS 策略沒有正確設置 Access-Control-Allow-Credentials: true,則會導致跨域請求失敗。同時,Access-Control-Allow-Origin 不能設置為 *Credentialstrue

3. 不支持的請求方法

如果請求使用了 CORS 策略中未明確允許的 HTTP 方法(如 PUT、PATCH、DELETE 等),請求也會被拒絕。只有正確聲明了 Access-Control-Allow-Methods 頭部,才能支持額外的方法。

4. 不允許的頭部字段

如果跨域請求中包含了服務器未通過 Access-Control-Allow-Headers 明確允許的頭部字段,請求將被瀏覽器攔截。這常見于自定義頭部,如 X-Custom-Header

5. 預檢請求失敗

復雜請求(如帶自定義頭或者特定方法的請求)首先會發送一個預檢(OPTIONS)請求,如果預檢請求沒有得到正確處理(如未返回允許的方法或頭部),實際請求不會被發送。

6. 瀏覽器的安全策略

不同瀏覽器對于跨域請求的處理可能略有差異,有些瀏覽器的安全策略可能更加嚴格。此外,瀏覽器的某些配置或擴展程序(如廣告攔截器或安全插件)可能阻止跨域請求。

7. 網絡問題或服務器不可達

服務器配置正確,但由于網絡問題或服務器宕機,導致請求無法到達服務器或服務器無法正確響應。

8. 錯誤的端口或協議

有時開發人員可能忽視了端口或協議的差異,這些細微的差別也會導致跨域錯誤,因為 CORS 是對協議、域名和端口都敏感的。

跨域行為實戰

我們可以在先前給出的服務 A 和服務 B 的代碼基礎上,通過修改設置和觀察結果來測試各種導致 CORS 設置不成功的情況。以下是針對每種情況的修改方法和預期的測試結果:

1. 錯誤的源設置

修改服務 B 來只接受來自 http://127.0.0.1:3001 的請求,而我們的請求實際上來自 http://localhost:3001

修改后的服務 B (api.js):

const express = require('express');
const cors = require('cors');
const app = express();app.use(cors({origin: 'http://127.0.0.1:3001', // 錯誤的源設置methods: ['GET'],credentials: true
}));app.get('/data', (req, res) => {res.json({ message: 'Successfully fetched cross-origin data from server B.' });
});app.listen(3002, () => {console.log('Server B running on http://localhost:3002');
});

預期結果: 瀏覽器控制臺將顯示類似于 "No 'Access-Control-Allow-Origin' header is present on the requested resource" 的錯誤,表示請求的源不被允許。

2. 忽略發送憑證

刪除或錯誤設置 Access-Control-Allow-Credentials,同時保留 credentials: 'include'

修改后的服務 B (api.js):

app.use(cors({origin: 'http://localhost:3001',methods: ['GET'],credentials: false // 錯誤地設置為 false
}));

預期結果: 瀏覽器控制臺會顯示錯誤,提示憑證不被允許,因為 credentials 屬性需要服務器明確允許。

3. 不支持的請求方法

假設我們嘗試發送一個 POST 請求,但服務 B 只允許 GET。

服務 A 發起 POST 請求 (public/index.html):

<script>
async function fetchData() {try {const response = await fetch('http://localhost:3002/data', {method: 'POST',credentials: 'include'});const data = await response.json();document.getElementById('data').textContent = JSON.stringify(data);} catch (error) {console.error('Error:', error);}
}
</script>

預期結果: 瀏覽器控制臺會顯示錯誤,指出使用了未被允許的方法。

4. 不允許的頭部字段

發送包含自定義頭部的請求,而服務 B 沒有允許這個頭部。

修改服務 A (public/index.html):

<script>
async function fetchData() {try {const response = await fetch('http://localhost:3002/data', {method: 'GET',credentials: 'include',headers: {'X-Custom-Header': 'value' // 添加不被允許的頭部}});const data = await response.json();document.getElementById('data').textContent = JSON.stringify(data);} catch (error) {console.error('Error:', error);}
}
</script>

預期結果: 瀏覽器控制臺將顯示錯誤,提示 "Request header field X-Custom-Header is not allowed"。

通過這些修改和測試,你可以更好地理解 CORS 設置可能出現的問題和如何解決這些問題。每次修改后,確保重啟服務并清空瀏覽器緩存,以確保測試結果的準確性。

服務端不做修改,瀏覽器如何避免cors

在 Web 開發中,瀏覽器的同源策略保護用戶免受惡意網站的攻擊,該策略禁止一個域的腳本與另一個域的資源進行交互。這意味著如果 CORS(跨源資源共享)策略不允許特定的跨源請求,那么在瀏覽器端通常沒有簡單的方法可以"避免"或"繞過" CORS 錯誤。這是一種安全機制,不應被繞過,特別是在生產環境中。

然而,對于開發測試目的,以下是幾種常用的方法來處理或繞過瀏覽器的 CORS 限制:

1. 使用代理服務器

在開發環境中,可以設置一個代理服務器,它接收你的請求,向目標服務器發送請求,并將響應返回給你的應用。這種方式常用于前端開發中,例如使用創建 React 應用的 create-react-app 工具,可以在 package.json 中添加一個代理配置:

"proxy": "http://localhost:3002",

這樣,所有對 /data 的請求將會被代理到 http://localhost:3002/data,而瀏覽器會認為這些請求仍然是同源的。

2. 使用瀏覽器插件

有些瀏覽器插件可以禁用或修改 CORS 策略,例如 "CORS Unblock" 等。這些插件通常用于開發和測試,但絕對不推薦在生產環境或瀏覽常規網站時使用,因為這會降低你的網絡安全防護。

如何使用 CORS Unblock
步驟 1: 安裝擴展
  1. Chrome 瀏覽器:

    • 打開 Chrome Web Store。
    • 在搜索框中輸入 “CORS Unblock”。
    • 找到擴展,點擊 “添加至 Chrome”。
  2. Firefox 瀏覽器:

    • 打開 Firefox Add-ons 網站。
    • 搜索 “CORS Unblock”。
    • 選擇擴展并點擊 “添加到 Firefox”。
步驟 2: 使用擴展

安裝擴展后,你會在瀏覽器的工具欄中看到 CORS Unblock 的圖標。你可以通過以下方式使用它:

  1. 激活/禁用 CORS Unblock:

    • 點擊瀏覽器工具欄中的 CORS Unblock 圖標。
    • 通常,擴展會有一個簡單的開關按鈕,允許你快速激活或禁用跨源請求限制。
    • 當擴展被激活時,圖標通常會變色(例如變為綠色),表示現在跨源請求的限制被禁用。
  2. 刷新頁面:

    • 在激活 CORS Unblock 后,刷新你正在工作的網頁。現在,頁面上的腳本應該能夠發出并接收原本因 CORS 策略而被阻止的請求。
步驟 3: 監控和調試
  • 使用瀏覽器的開發者工具(通常可以通過右鍵點擊頁面并選擇“檢查”來打開)來監控網絡請求和響應。
  • 檢查網絡標簽,確保之前因 CORS 錯誤被阻止的請求現在是否成功。

3. 配置瀏覽器啟動參數

對于 Chrome 瀏覽器,可以通過添加啟動參數來禁用安全特性,這包括 CORS 檢查。可以使用以下命令啟動 Chrome(僅在本地開發時使用):

chrome.exe --disable-web-security --user-data-dir="C:/ChromeDevSession"

這將開啟一個新的 Chrome 會話,其中禁用了跨域安全檢查。注意,這種方法僅應在完全控制的開發環境中使用,且必須保證不會瀏覽任何潛在的惡意網站。

4. 修改服務器配置(理想方式)

雖然這不是瀏覽器端的解決方案,但修改服務器以發送正確的 CORS 頭部是解決跨域問題的最佳實踐。這包括正確配置 Access-Control-Allow-Origin 和相關的 CORS 頭部。這是最安全和最可靠的解決方案。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/39595.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/39595.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/39595.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

如何無線連接ios,自動化穩定

如果你的iPhone的USB端口無法使用&#xff0c;但你需要進行自動化測試或其他操作&#xff0c;可以通過無線連接來實現。無線連接通常涉及到使用Wi-Fi網絡&#xff0c;這樣你就可以在不使用USB線的情況下與設備交互。以下是一些可以考慮的方法&#xff1a; 1.使用Xcode進行無線…

William Yang:從區塊鏈先鋒到藝術平臺創始人

在區塊鏈技術和加密貨幣市場飛速發展的今天&#xff0c;William Yang無疑是這一領域的佼佼者。他不僅在學術和媒體領域取得了顯著成就&#xff0c;更在創業之路上不斷探索&#xff0c;成為了業內知名的KOL&#xff08;關鍵意見領袖&#xff09;。今天&#xff0c;我們有幸采訪到…

AI姓氏頭像生成微信小程序系統源碼

&#x1f525;【科技新潮流】AI姓氏頭像生成系統&#xff0c;你的專屬個性新名片&#xff01;&#x1f389; &#x1f31f; 開篇驚艷&#xff1a;一鍵解鎖你的姓氏魅力 ? Hey小伙伴們&#xff0c;今天我要安利一個超酷炫的科技小玩意——AI姓氏頭像生成系統&#xff01;是不…

js字符串序列化為二進制數據

在JavaScript中&#xff0c;可以通過不同的方式將字符串序列化為二進制數據。以下是幾種常見的方法&#xff1a; TextEncoder 和 TextDecoder JavaScript 提供了 TextEncoder 和 TextDecoder 對象&#xff0c;可以用來處理字符串和二進制數據之間的轉換。 // 將字符串轉換為二進…

MySQL Server時區支持

本文介紹MySQL維護的時區設置——如何加載命名時間支持所需的系統表&#xff0c;如何及時了解時區變化&#xff0c;以及如何啟用閏秒支持。 從MySQL 8.0.19開始&#xff0c;插入的日期時間值也支持時區偏移。 1 時區變量 MySQL Server維護了幾個時區設置&#xff1a; 服務器…

爬蟲筆記20——票星球搶票腳本的實現

以下內容僅供交流學習使用&#xff01;&#xff01;&#xff01; 思路分析 前面的爬蟲筆記一步一步走過來我們的技術水平也有了較大的提升了&#xff0c;現在我們來進行一下票星球搶票實戰項目&#xff0c;實現票星球的自動搶票。 我們打開票星球的移動端頁面&#xff0c;分…

視頻字幕提取在線工具有哪些?總結5個字幕提取工具

平時在沉浸式追劇的時候&#xff0c;我們常常都會被影視劇中的各種金句爆梗而逗得開懷大笑~而真正要用到時候卻總是一片頭腦空白。其實要記住它們最好的辦法便是將其提取留檔下來&#xff0c;每次有需要的時候打開就能一下子回顧到~ 今天就來帶大家盤一盤視頻字幕提取的軟件好…

高考假期預習指南

人不走空 &#x1f308;個人主頁&#xff1a;人不走空 &#x1f496;系列專欄&#xff1a;算法專題 ?詩詞歌賦&#xff1a;斯是陋室&#xff0c;惟吾德馨 目錄 &#x1f308;個人主頁&#xff1a;人不走空 &#x1f496;系列專欄&#xff1a;算法專題 ?詩詞歌…

目標檢測YOLO實戰應用案例100講-基于深度學習的無人機影像小目標識別

目錄 前言 研究現狀 深度學習研究現狀 目標檢測研究現狀 目標檢測存在的問題 2 基于深度學習的目標檢測算法理論基礎 2.1 卷積神經網絡 2.1.1 卷積層 2.1.2 池化層 2.1.3 激活函數 2.1.4 全連接層 2.2 優化器 2.3 基于深度學習的目標檢測算法 2.3.1 …

樹上差分的公式推導

今天寫了一道題目&#xff0c;需要采用線段樹合并樹上差分來解決 題目鏈接&#xff1a;P1600 [NOIP2016 提高組] 天天愛跑步 - 洛谷 | 計算機科學教育新生態 (luogu.com.cn) 其實當時已經想到要用這兩種方法&#xff0c;但苦于一直找不到轉移方程&#xff0c;最后看了答案才領…

java中可變參數

在Java中&#xff0c;... 是可變參數&#xff08;varargs&#xff09;的語法&#xff0c;用于允許一個方法接受可變數量的參數。可變參數的引入使得方法調用更加靈活和簡潔。以下是對可變參數的詳細解釋和使用示例。 可變參數的定義和使用 定義&#xff1a; 在方法參數列表中…

22-Pandas日期時間格式化

Pandas日期時間格式化 當進行數據分析時&#xff0c;我們會遇到很多帶有日期、時間格式的數據集&#xff0c;在處理這些數據集時&#xff0c;可能會遇到日期格式不統一的問題&#xff0c;此時就需要對日期時間做統一的格式化處理。比如“Wednesday, June 6, 2020”可以寫成“6…

Rust: polars行遍歷,從dataframe到struct及Bar設計比較

pandas提供了iterrows()、itertuples()、apply等行遍歷的方式&#xff0c;還是比較方便的。 polars的列操作功能非常強大&#xff0c;這個在其官網上有詳細的介紹。由于polars底層的arrow是列存儲模式&#xff0c;行操作效率低下&#xff0c;官方也不推薦以行方式進行數據操作。…

react_后臺管理_項目

目錄 1.運行項目 2. 項目結構 ①項目頂部導航欄 ②項目左側導航欄 ③主頁面-路由切換區 本項目使用的是 reacttsscss 技術棧。 1.運行項目 在當前頁面頂部下載本項目&#xff0c;解壓后使用編輯器打開&#xff0c;然后再終端輸入命令&#xff1a; npm i 下載依賴后&am…

【應急響應】Windows應急響應 - 基礎命令篇

前言 在如今的數字化時代&#xff0c;Windows系統面對著越來越復雜的網絡威脅和安全挑戰。本文將深入探討在Windows環境下的實戰應急響應策略。我們將重點關注實際應急響應流程、關鍵工具的應用&#xff0c;以及如何快速準確地識別和應對安全事件。通過分享實際案例分析&#…

FIO壓測磁盤性能以及需要注意的問題

一、壓測類型 1、順序讀&#xff08;IO&#xff09;&#xff1a;read&#xff0c;bs1M&#xff0c;job數從1開始往上加&#xff1a;2、3、4... 2、順序寫&#xff08;IO&#xff09;&#xff1a;write&#xff0c;bs1M&#xff0c;job數從1開始往上加&#xff1a;2、3、4... …

如何通過 1688 商品詳情的 API 接口獲取商品的詳細信息

在當今數字化商業的大背景下&#xff0c;能夠從 1688 這樣規模龐大且商品種類豐富的電商平臺中準確、高效地獲取商品的詳細信息&#xff0c;對于眾多企業和開發者而言&#xff0c;具有舉足輕重的意義。而通過 1688 商品詳情的 API 接口來實現這一目標&#xff0c;無疑是一種強大…

【ACM出版,馬來西亞-吉隆坡舉行】第四屆互聯網技術與教育信息化國際會議 (ITEI 2024)

作為全球科技創新大趨勢的引領者&#xff0c;中國不斷營造更加開放的科技創新環境&#xff0c;不斷提升學術合作的深度和廣度&#xff0c;構建惠及各方的創新共同體。這是對全球化的新貢獻&#xff0c;是構建人類命運共同體的新貢獻。 第四屆互聯網技術與教育信息化國際學術會議…

【 木蘭寬松許可證】

木蘭寬松許可證&#xff0c; 第1版 2019年8月 http://license.coscl.org.cn/MulanPSL 您對“軟件”的復制、使用、修改及分發受木蘭寬松許可證&#xff0c;第1版&#xff08;“本許可證”&#xff09;的如下條款的約束&#xff1a; 定義 “軟件”是指由“貢獻”構成的許可在“本…

【C++知識點總結全系列 (07)】:模板與泛型編程詳細總結與分析

模板與泛型編程 1、概述(1)What&#xff08;什么是模板、泛型編程&#xff09;(2)Why(3)Which(4)模板參數A.WhatB.HowC.模板參數的類型成員D.默認模板參數 2、模板函數3、模板類(1)How&#xff08;如何定義和使用模板類&#xff09;(2)成員模板 4、模板實參推斷(1)What&#xf…