seo網(wǎng)站推廣優(yōu)化站長工具綜合查詢官網(wǎng)
1.什么是跨域
跨域問題的實質(zhì)是瀏覽器的同源策略造成的。瀏覽器同源策略是瀏覽器為 JavaScript
施加的限制。簡單點說就是非同源會出現(xiàn)如下等限制:
- 無法訪問其他源下的網(wǎng)頁的 Cookies,Storage等;
- 無法訪問其他源下的DOM對象和 JS 對象;
- 無法使用 Ajax 向其他源發(fā)送請求(除非其他源允許)
那什么情況下會出現(xiàn)限制呢?也就是什么時候會出現(xiàn)跨域?
前提:必須運行在瀏覽器中。因為同源策略是瀏覽器對 JS 施加的
- 協(xié)議不同。http://abc.com:80 的網(wǎng)頁訪問 https://abc.com:80
- 主機名不同。https://abc.com:80 的網(wǎng)頁訪問 https://cde.com:80 / https://api.abc.com:80 (子域名也不行)
- 端口不同。https://abc.com:80 的網(wǎng)頁訪問 https://abc.com:443
舉個栗子
前端運行地址:127.0.0.1:3000
import React, { useState } from "react";const App = () => {const [data, setData] = useState(null);const fetchData = async () => {try {const response = await fetch('http://127.0.0.1:8080/test');const data = await response.json();setData(data);} catch (error) {console.error('Error:', error);}};return (<div><button onClick={fetchData}>Fetch</button>{data && <pre>{JSON.stringify(data, null, 2)}</pre>}</div>);
};
export default App;
后端運行地址:127.0.0.1:8080
@RestController
public class TestController {@GetMapping("/test")public Map<String, Object> test(HttpServletResponse response) {return new HashMap<String, Object>() {{put("ok" , true);}};}
}
點擊 Fetch 后,產(chǎn)生跨域
2.為什么要有同源策略
Web的同源策略是一種瀏覽器安全機制,被設(shè)計用于保護用戶信息和防止惡意攻擊。同源策略要求瀏覽器在加載網(wǎng)頁時,只允許與當前頁面具有相同源的資源進行交互,即協(xié)議、域名和端口必須完全相同。
同源策略的主要目的是防止惡意網(wǎng)站通過跨站腳本攻擊(XSS)或跨站請求偽造(CSRF)等方式獲取用戶的敏感信息或進行惡意操作。
具體原因如下:
-
防止信息泄露:同源策略阻止惡意的網(wǎng)站訪問其他域名下的數(shù)據(jù)和文檔對象模型(DOM)。這是因為在不同域下的網(wǎng)頁很可能具有不同的安全性控制政策和訪問權(quán)限,所以限制跨域訪問有助于保護用戶的敏感信息,如登錄憑據(jù)、Cookie、本地存儲等。
-
數(shù)據(jù)隔離:同源策略確保網(wǎng)站之間的數(shù)據(jù)相互隔離,防止一個網(wǎng)站的惡意代碼或攻擊不會影響其他網(wǎng)站的數(shù)據(jù)完整性和可用性。此舉有助于防止一些常見的攻擊,如點擊劫持和防止惡意腳本對其他網(wǎng)站進行操作。
-
安全性和可靠性:同源策略有助于維護瀏覽器的安全性和穩(wěn)定性。通過限制跨域訪問,它可以減少惡意代碼的傳播,并減少對瀏覽器的影響。
雖然同源策略在保護用戶信息和防止惡意攻擊方面非常重要,但有時也會帶來一定的限制。因此,如果確實需要在不同源之間進行數(shù)據(jù)交互,可以使用跨域資源共享(CORS)等安全機制來規(guī)避同源策略的限制。
(來自ChatGPT)
3.怎么解決跨域問題,即繞過同源策略限制
跨域?qū)嵗?#xff0c;前端和后端運行的端口不同(前端3000,后端8080)所以導(dǎo)致了跨域。如果想要前端能直接訪問后端,有什么辦法呢?
3.1 服務(wù)端設(shè)置CORS
這是最簡單的辦法,在后端加上配置允許所有的源地址訪問:
"Access-Control-Allow-Origin" : "*"
@RestController
public class TestController {@GetMapping("/test")public Map<String, Object> test(HttpServletResponse response) {// 這是最核心的配置,可以使用更加優(yōu)雅的方式,@CrossOrigin注解、攔截器、過濾器等response.setHeader("Access-Control-Allow-Origin" , "*");return new HashMap<String, Object>() {{put("ok" , true);}};}
}
3.2 代理
代理的核心是讓瀏覽器頁面訪問一個同源的服務(wù)端,讓同源服務(wù)端去獲取頁面想要的資源。
Nginx 中:
server {listen 3000;server_name 127.0.0.1;location /api {proxy_pass http://localhost:8080;}
}
Node 中:(以 開發(fā)React 應(yīng)用為例)
const proxy = require('http-proxy-middleware');
module.exports = function (app) {app.use('/api',proxy({target : 'http://127.0.0.1:8080/',changeOrigin : true,PathRewrite : {'^/api' : ''}}));
};
3.3 JSONP
簡單來說就是利用 HTML 標簽來訪問跨域的資源(因為同源策略是瀏覽器為 JavaScript
施加的限制)
前端準備好callback方法和請求的標簽
<!DOCTYPE html>
<html lang="en"><head><meta charset="utf-8" /><title>React App</title><script>// 準備好回調(diào)的方法const callback = (data) => {console.log("data", data);}</script><!-- 通過訪問接口,獲取模擬的 data 入?yún)?--><script src="http://127.0.0.1:8080/jsonp"></script></head><body><div id="root"></div></body>
</html>
后端增加接口,模擬返回 JS 腳本:
@GetMapping("/jsonp")
public String jsonp() {return "callback({\"ok\": false});";
}