前端怎麼解決跨域問題

喆星高照發表於2024-06-05

前端跨域問題的解決方案通常涉及幾種不同的方法,每種方法都有其特定的應用場景和優缺點。以下是一些常見的前端跨域解決方案:

  1. JSONP(JSON with Padding)
    • 原理:利用<script>標籤沒有跨域限制的特性,透過動態建立<script>標籤並設定其src屬性為跨域請求的URL,來實現跨域資料獲取。
    • 實現方式:在前端定義一個回撥函式,然後在跨域請求URL的末尾新增這個回撥函式的名稱作為引數。伺服器端在返回資料時,會將資料作為這個回撥函式的引數返回。前端接收到資料後,會執行這個回撥函式,從而獲取到資料。
    • 缺點:只能支援GET請求,存在安全風險(如XSS攻擊),且不能傳送自定義的HTTP頭。
  2. CORS(Cross-Origin Resource Sharing)
    • 原理:一種由W3C規範定義的跨域資源共享機制,它允許網頁上的JavaScript程式碼向其他源(域名、協議、埠任一不同)的伺服器發出請求,並獲取資料。
    • 實現方式:在後端伺服器設定響應頭(如Access-Control-Allow-Origin),允許指定的源進行跨域訪問。前端程式碼無需修改,直接使用標準的AJAX或Fetch API發起請求即可。
    • 優點:支援所有型別的HTTP請求,包括GET、POST、PUT、DELETE等,且可以傳送自定義的HTTP頭。
  3. 代理伺服器
    • 原理:透過在前端和後端之間設定一個代理伺服器,將前端發起的跨域請求轉發給後端伺服器,然後將後端伺服器的響應轉發給前端。由於代理伺服器和前端、後端都是同源的,因此可以規避瀏覽器的同源策略限制。
    • 實現方式:常見的代理伺服器軟體有Nginx、Node.js等。可以在這些軟體中配置代理規則,將前端發起的跨域請求轉發到指定的後端伺服器。
    • 優點:靈活性強,可以自定義代理規則,支援所有型別的HTTP請求和自定義HTTP頭。
  4. 其他解決方案
    • document.domain + iframe:僅限主域相同、子域不同的應用場景。透過設定document.domain為基礎主域,可以實現同域,從而互相操作資源。
    • location.hash + iframe:父頁面改變iframe的src屬性,location.hash的值改變,不會重新整理頁面。在子頁面可以透過window.location.hash獲取到父頁面傳遞的資料。

在實際開發中,應根據具體的業務需求和場景選擇合適的跨域解決方案。例如,如果只需要支援GET請求且對安全性要求不高,可以選擇JSONP;如果需要支援所有型別的HTTP請求且需要傳送自定義的HTTP頭,可以選擇CORS;如果需要更靈活的配置和自定義規則,可以選擇代理伺服器。

當然,我會為每種解決方案提供一個簡單的示例程式碼。

1. JSONP

前端程式碼(使用 jQuery 的 $.ajax 方法作為示例):

function fetchDataJsonp(url, callbackParam, callbackFunction) {  
    var script = document.createElement('script');  
    script.src = url + (url.indexOf('?') >= 0 ? '&' : '?') + callbackParam + '=' + callbackFunction.name;  
    document.body.appendChild(script);  
}  
  
function handleData(data) {  
    console.log(data);  
}  
  
// 假設後端服務返回類似 `handleData({"name": "John", "age": 30});`  
fetchDataJsonp('https://example.com/api/data', 'callback', handleData);

注意:JSONP 需要後端服務支援特定的回撥函式格式。

2. CORS

前端程式碼(使用原生的 fetch API):

fetch('https://example.com/api/data', {  
    method: 'GET',  
    headers: {  
        'Content-Type': 'application/json',  
    },  
})  
.then(response => response.json())  
.then(data => console.log(data))  
.catch((error) => {  
    console.error('Error:', error);  
});

後端需要設定 CORS 相關的響應頭,例如:

Access-Control-Allow-Origin: *  
Access-Control-Allow-Methods: GET, POST, OPTIONS  
Access-Control-Allow-Headers: Content-Type

注意:* 表示允許所有源訪問,但在生產環境中,為了安全起見,應該只允許特定的源。

3. 代理伺服器(使用 Node.js 的 Express 作為示例)

前端程式碼(與 CORS 示例相同,因為請求是透過代理伺服器傳送的,所以前端程式碼不需要更改):

fetch('https://example.com/api/data', {  
    method: 'GET',  
    headers: {  
        'Content-Type': 'application/json',  
    },  
})  
.then(response => response.json())  
.then(data => console.log(data))  
.catch((error) => {  
    console.error('Error:', error);  
});

Node.js Express 代理伺服器示例:

const express = require('express');  
const request = require('request');  
const app = express();  
  
app.use('/api', (req, res) => {  
    request({  
        url: 'https://example.com/api' + req.url,  
        method: req.method,  
        headers: req.headers,  
        body: req.body  
    }).pipe(res);  
});  
  
app.listen(3000, () => {  
    console.log('Proxy server listening on port 3000');  
});

注意:上面的代理伺服器示例使用了 request 庫來轉發請求,但在新的 Node.js 版本中,你可能需要使用 axiosnode-fetch 或其他庫來替代 request,因為 request 庫已經廢棄。

相關文章