一文盤點(diǎn)SpringBoot中常用跨域處理方案
1.什么是跨域
跨域是瀏覽器為了保障安全而遵循的一種規(guī)則,是同源策略的一部分。
- 同源:要求協(xié)議、域名、端口三者完全相同。
- 跨域:只要協(xié)議、域名、端口中有任何一個(gè)不同,瀏覽器就會判定為跨域請求。
跨域(Cross-Origin)是瀏覽器獨(dú)有的安全策略,不存在于安卓、iOS、Node.js、Python、Java 等原生客戶端或服務(wù)器端環(huán)境中。因?yàn)闉g覽器是一個(gè)開放的、執(zhí)行不可信代碼,也就是各個(gè)網(wǎng)站的 js 腳本的環(huán)境,同源策略是為了保證用戶的信息安全。
所以,如果平時(shí)測試接口用的是 postman 發(fā)送請求,不需要關(guān)心跨域問題,但是如果是前后端聯(lián)調(diào)就必須處理跨域問題。
2.瀏覽器處理跨域請求的方式
瀏覽器遵循同源策略,不允許頁面獲取跨域請求返回的響應(yīng)結(jié)果。
比如:當(dāng)前網(wǎng)頁是 http://127.0.0.1:63342,然后向服務(wù)器 http://127.0.0.1:8080 發(fā)送 GET 請求獲取數(shù)據(jù)。整個(gè)過程分成三步:
- 瀏覽器發(fā)送請求
- 服務(wù)器接收請求,處理業(yè)務(wù),返回響應(yīng)
- 瀏覽器獲取服務(wù)器返回的響應(yīng)并根據(jù)響應(yīng)渲染頁面
無論是跨域請求還是非跨域請求,瀏覽器都可以發(fā)送給服務(wù)器,并且接收服務(wù)器返回的響應(yīng)數(shù)據(jù)。
- 如果該請求是非跨域請求,則 js 腳本可以訪問響應(yīng)數(shù)據(jù)
- 如果該請求是跨域請求,瀏覽器會攔截響應(yīng)數(shù)據(jù),不讓 js 訪問這些數(shù)據(jù)
其實(shí)瀏覽器可以向不同的域名發(fā)送請求,但是瀏覽器會攔截響應(yīng)內(nèi)容,不讓 js 訪問,無論請求是否成功。
3.跨域處理方案
跨域處理的核心:讓瀏覽器不要攔截跨域請求返回的數(shù)據(jù)。
服務(wù)器的響應(yīng)中如果有 Access-Control-Allow-Origin: * 這個(gè)響應(yīng)頭,就是告訴瀏覽器:"我是服務(wù)器,雖然我跟這個(gè)網(wǎng)頁不是同源的,但是我允許這個(gè)網(wǎng)頁跟我通信,我們之間的通信是安全的",瀏覽器就不會攔截 js 對響應(yīng)數(shù)據(jù)的訪問。
瀏覽器發(fā)送的請求可以分為簡單請求和復(fù)雜請求:
- 如果是簡單請求,則瀏覽器直接發(fā)送。
- 如果是復(fù)雜請求,則瀏覽器先發(fā)送一個(gè)預(yù)檢請求,即 OPTIONS 請求,問一句:"我可以發(fā)送一個(gè)超級復(fù)雜的跨域請求嗎?",服務(wù)器需要返回針對 OPTIONS 的響應(yīng)。如果服務(wù)器允許發(fā)送這個(gè)復(fù)雜請求,瀏覽器才會真正發(fā)送請求。
常見的跨域處理方案有:代理服務(wù)器、后端服務(wù)器跨域配置。
3.1代理服務(wù)器
瀏覽器將請求發(fā)送到跟頁面同源的代理服務(wù)器,代理服務(wù)器再將請求轉(zhuǎn)發(fā)到目標(biāo)服務(wù)器。因?yàn)榉?wù)器間通信不受同源策略限制。比如常見的用 nginx 作為代理服務(wù)器。
請求處理過程:
- 前端發(fā)送請求,請求經(jīng)過 nginx,請求被轉(zhuǎn)發(fā)到后端服務(wù)器。
- 服務(wù)器返回原始響應(yīng),原始響應(yīng)經(jīng)過 nginx,nginx 自動添加 Access-Control-Allow-Origin: * 響應(yīng)頭,響應(yīng)返回給前端,js 可以訪問響應(yīng)數(shù)據(jù)。
# nginx.conf
server {
listen 63342;
# 前端頁面的域名或ip
server_name 127.0.0.1;
# 代理所有以 /api/ 開頭的請求到后端服務(wù)器
location /api/ {
# 后端服務(wù)器地址
proxy_pass http://127.0.0.1:8080/;
# 修改請求頭,確保后端能收到正確的原始主機(jī)信息
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# 添加CORS響應(yīng)頭,允許所有來源的請求,生產(chǎn)環(huán)境應(yīng)關(guān)閉
add_header 'Access-Control-Allow-Origin' '*';
# 允許的請求方法
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE, PATCH';
if ($request_method = 'OPTIONS') {
# 對于OPTIONS請求,直接返回204狀態(tài)碼,不需要轉(zhuǎn)發(fā)到后端
return 204;
}
}
}
3.2 后端跨域配置
3.2.1 配置 CORS
配置全局 CORS 規(guī)則,在所有響應(yīng)頭都配置可以跨域訪問。
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") // 允許所有接口跨域
.allowCredentials(true) // 允許瀏覽器在跨域請求中發(fā)送認(rèn)證信息
.allowedOriginPatterns("*") // 允許訪問資源的源(協(xié)議、域名、端口)
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") // 允許的方法
.allowedHeaders("*") // 允許的請求頭
.exposedHeaders("*"); // 哪些響應(yīng)頭可以暴露給前端js
}
}
3.2.2 提供 CorsFilter
提供一個(gè) CorsFilter 的 Bean 作為過濾器。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
@Configuration
public class MyCorsFilter {
@Bean
public CorsFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOriginPattern("*"); // 放行所有域名,生產(chǎn)環(huán)境請對此進(jìn)行修改
config.setAllowCredentials(true); // 是否發(fā)送cookie
config.addAllowedMethod("*"); // 放行的請求方式
config.addAllowedHeader("*"); // 放行的請求頭
config.addExposedHeader("*"); // 暴露頭部信息
// UrlBasedCorsConfigurationSource: 可以為不同的URL路徑設(shè)置不同的CORS規(guī)則
UrlBasedCorsConfigurationSource corsConfigurationSource = new UrlBasedCorsConfigurationSource();
// 所有的URL路徑都使用同一個(gè)CORS規(guī)則
corsConfigurationSource.registerCorsConfiguration("/**", config);
return new CorsFilter(corsConfigurationSource);
}
}
3.2.3 @CrossOrigin 注解
在接口類上或者接口方法上添加 @CrossOrigin 注解,表示整個(gè)類、單個(gè)接口的響應(yīng)不會被攔截。
@RestController
@CrossOrigin
public class DemoController {
@PutMapping("/put")
public Integer put(MultipartFile file) {
System.out.println(file.getOriginalFilename());
return 200;
}
@GetMapping("/get")
public Integer get() {
return 200;
}
}
到此這篇關(guān)于一文盤點(diǎn)SpringBoot中常用跨域處理方案的文章就介紹到這了,更多相關(guān)SpringBoot跨域處理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java基礎(chǔ)之內(nèi)部類與代理知識總結(jié)
今天帶大家復(fù)習(xí)Java的基礎(chǔ)知識,文中有非常詳細(xì)的介紹及圖文示例,對正在學(xué)習(xí)Java的小伙伴們很有幫助,需要的朋友可以參考下2021-06-06
利用ThreadLocal實(shí)現(xiàn)一個(gè)上下文管理組件
本文基于ThreadLocal原理,實(shí)現(xiàn)了一個(gè)上下文狀態(tài)管理組件Scope,通過開啟一個(gè)自定義的Scope,在Scope范圍內(nèi),可以通過Scope各個(gè)方法讀寫數(shù)據(jù),感興趣的可以了解一下2022-10-10
Java?web開發(fā)環(huán)境的搭建超完整步驟
這篇文章主要介紹了如何安裝和配置IDEA?2020.1.1?X64版本軟件,包括創(chuàng)建Java?Web項(xiàng)目、配置Tomcat、部署Tomcat?API以及創(chuàng)建和配置Servlet,通過這些步驟,新手可以快速搭建起Javaweb開發(fā)環(huán)境,需要的朋友可以參考下2024-11-11
Java實(shí)現(xiàn)查找文件和替換文件內(nèi)容
這篇文章主要為大家詳細(xì)介紹了Java語言如何實(shí)現(xiàn)查找文件和替換文件內(nèi)容功能,文中的示例代碼講解詳細(xì),感興趣的可以跟隨小編一起學(xué)習(xí)一下2022-08-08

