跨域問(wèn)題及常用的四種解決方案
圖片
前言
跨域問(wèn)題指的是在Web開(kāi)發(fā)中,由于瀏覽器的同源策略限制,當(dāng)一個(gè)網(wǎng)頁(yè)嘗試訪問(wèn)與它不同源(協(xié)議、域名或端口不同)的資源時(shí),可能會(huì)遇到安全限制導(dǎo)致無(wú)法正常訪問(wèn)的問(wèn)題。這種策略旨在防止惡意網(wǎng)站讀取或修改其他網(wǎng)站的數(shù)據(jù),保護(hù)用戶(hù)信息安全。
這樣說(shuō)可能有點(diǎn)抽象,下面具體展開(kāi)說(shuō)明。
跨域問(wèn)題演示
通常情況下,我們主流的開(kāi)發(fā)模式是:前后端分離。當(dāng)我們從瀏覽器80訪問(wèn)服務(wù)端81應(yīng)用
圖片
下面我們用一個(gè)Web工程,一個(gè)后端工程具體簡(jiǎn)單演示下。
1、Web工程結(jié)構(gòu):
圖片
- application.properties
spring.application.name=springboot-cross-web
server.port=8080
- index.html 頁(yè)面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>測(cè)試跨域請(qǐng)求頁(yè)面</title>
<script src="js/jquery-3.5.1.min.js"></script>
</head>
<body>
<div>
<input type="button" onclick="crossSubmit()" value="跨域測(cè)試">
</div>
<script>
function crossSubmit() {
// 發(fā)送跨域請(qǐng)求
jQuery.ajax({
url: "http://localhost:8081/api/cross",
type: "POST",
data: {"key": "Cross"},
success: function (result) {
alert("返回?cái)?shù)據(jù):" + result.data);
}
});
}
</script>
</body>
</html>
2、后端工程結(jié)構(gòu):
圖片
- application.properties
spring.application.name=springboot-cross
server.port=8081
- 測(cè)試應(yīng)用
@RestController
public class CrossAppController {
@RequestMapping("/api/cross")
public HashMap<String, Object> crossTest() {
return new HashMap<String, Object>() {{
put("state", 200);
put("data", "success");
}};
}
}
3、啟動(dòng)并測(cè)試
圖片
瀏覽器報(bào)錯(cuò)產(chǎn)生跨域問(wèn)題。
為什么產(chǎn)生跨域問(wèn)題?
一般來(lái)講,通常產(chǎn)生跨域問(wèn)題有以下幾種原因:
- 協(xié)議不同:如 https和http;
- 端口不同
- 域名不同
圖片
這就是常說(shuō)的同源策略的問(wèn)題。產(chǎn)生跨域問(wèn)題的根源就是請(qǐng)求不同源。
如何解決跨域問(wèn)題?
從上邊的問(wèn)題來(lái)看,主要在于瀏覽器保護(hù),對(duì)參數(shù) "Access-Control-Allow-Origin"的設(shè)置。
主要有下解決方案:
一、使用@CrossOrigin注解
@RestController
@CrossOrigin(origins = "*")
public class CrossAppController {
@RequestMapping("/api/cross")
public HashMap<String, Object> crossTest() {
return new HashMap<String, Object>() {{
put("state", 200);
put("data", "success");
}};
}
}
演示結(jié)果:
圖片
二、使用全局跨域配置
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/cross")
.allowedOrigins("*")
.allowedMethods("GET", "POST", "PUT", "DELETE")
.allowedHeaders("*");
//.allowCredentials(true);
}
}
三、使用CorsFilter跨域
@Component
public class CorsFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request = (HttpServletRequest) req;
// 設(shè)置允許的來(lái)源
response.setHeader("Access-Control-Allow-Origin", "*");
// 處理預(yù)檢請(qǐng)求
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, res);
}
}
}
四、使用Nginx來(lái)實(shí)現(xiàn)跨域
server {
listen 80;
server_name your.domain.com;
location / {
# 添加CORS相關(guān)的響應(yīng)頭
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
# 對(duì)于OPTIONS請(qǐng)求,直接返回204狀態(tài)碼
if ($request_method = 'OPTIONS') {
return 204;
}
# 其他配置...
# 代理到后端服務(wù)或其他配置...
# proxy_pass http://your_backend/;
# 其他proxy_...指令...
}
}
總結(jié)
- 跨域問(wèn)題指的是在Web開(kāi)發(fā)中,由于瀏覽器的同源策略限制,導(dǎo)致無(wú)法正常訪問(wèn)的問(wèn)題。
- 主要原理就是請(qǐng)求參數(shù)Access-Control-Allow-Origin
參考文章: https://mp.weixin.qq.com/s/YQr0q4qeZb5p1s-FVEdJvg