Java 中的跨域問(wèn)題解決方法
1、Java 中跨域問(wèn)題的來(lái)源
跨域問(wèn)題(Cross-Origin Resource Sharing, CORS)本質(zhì)上是瀏覽器的一種安全機(jī)制,與Java本身無(wú)關(guān),但Java后端開(kāi)發(fā)者需要理解其來(lái)源以便正確解決。以下是跨域問(wèn)題的詳細(xì)來(lái)源分析:
1.1. 瀏覽器同源策略(Same-Origin Policy)
- 根本來(lái)源:瀏覽器出于安全考慮實(shí)施的同源策略
- 同源定義:協(xié)議(http/https)+域名+端口三者完全相同
- 限制內(nèi)容:限制不同源的DOM訪問(wèn),限制不同源的AJAX請(qǐng)求,限制不同源的Cookie/LocalStorage訪問(wèn)
1.2. Java后端常見(jiàn)的跨域觸發(fā)場(chǎng)景
1.2.1 前后端分離架構(gòu)

開(kāi)發(fā)時(shí)前端與后端運(yùn)行在不同端口
生產(chǎn)環(huán)境前端與后端可能部署在不同域名下
1.2.2 微服務(wù)架構(gòu)

網(wǎng)關(guān)與服務(wù)可能在不同域
服務(wù)間調(diào)用也可能涉及跨域
1.2.3 第三方API集成
調(diào)用外部服務(wù)如支付接口、地圖API等
1.3. Java中具體的跨域表現(xiàn)
1.3.1 典型錯(cuò)誤
Access to XMLHttpRequest at 'http://api.example.com' from origin 'http://frontend.com'
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present
on the requested resource.
1.3.2 觸發(fā)條件

1.4. Java特有的跨域問(wèn)題來(lái)源
1.4.1 Spring Security默認(rèn)配置
Spring Security默認(rèn)啟用CSRF保護(hù)
會(huì)與CORS機(jī)制產(chǎn)生沖突
1.4.2 Servlet容器行為
Tomcat/Jetty等容器默認(rèn)不帶CORS頭
過(guò)濾器鏈順序可能影響CORS處理
1.4.3 傳統(tǒng)Java Web應(yīng)用
JSP時(shí)代頁(yè)面和后端同源,現(xiàn)代前后端分離導(dǎo)致問(wèn)題顯現(xiàn)
1.5. 為什么需要Java端解決
瀏覽器行為不可控:同源策略是瀏覽器強(qiáng)制實(shí)施的
安全責(zé)任在后端:哪些源可以訪問(wèn)應(yīng)由后端決定
靈活控制需求:不同接口可能需要不同的跨域策略
1.6. 特殊注意事項(xiàng)
Cookie跨域:需要設(shè)置Access-Control-Allow-Credentials: true
自定義頭跨域:需在Access-Control-Allow-Headers中聲明
緩存問(wèn)題:合理設(shè)置Access-Control-Max-Age提高性能
2、Java 中解決跨域問(wèn)題的方法
跨域問(wèn)題是由于瀏覽器的同源策略(Same-Origin Policy)導(dǎo)致的,當(dāng)你的前端應(yīng)用(如運(yùn)行在 http://localhost:8080)嘗試訪問(wèn)不同源(如 http://api.example.com)的后端API時(shí),瀏覽器會(huì)阻止這種請(qǐng)求。以下是Java中常見(jiàn)的跨域解決方案:
2.1. Spring Boot 解決方案
2.1.1 使用 @CrossOrigin 注解
@RestController
@RequestMapping("/api")
public class MyController {
// 允許單個(gè)方法跨域
@CrossOrigin(origins = "http://localhost:3000")
@GetMapping("/hello")
public String hello() {
return "Hello, CORS!";
}
// 允許整個(gè)控制器跨域
@CrossOrigin(origins = "http://localhost:3000")
@GetMapping("/another")
public String another() {
return "Another endpoint";
}
}2.1.2 全局配置跨域
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") // 所有路徑
.allowedOrigins("http://localhost:3000", "https://example.com") // 允許的源
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") // 允許的方法
.allowedHeaders("*") // 允許的請(qǐng)求頭
.allowCredentials(true) // 允許攜帶憑證(cookie等)
.maxAge(3600); // 預(yù)檢請(qǐng)求的緩存時(shí)間(秒)
}
}2.2. 傳統(tǒng) Servlet 解決方案
2.2.1 使用 Filter
/**
* CORS跨域過(guò)濾器配置
* 用于處理瀏覽器跨域請(qǐng)求的支持
* 過(guò)濾器會(huì)攔截所有請(qǐng)求(/*)并添加CORS響應(yīng)頭
*/
@WebFilter("/*") // 攔截所有請(qǐng)求
public class CorsFilter implements Filter {
/**
* 過(guò)濾器核心方法,處理請(qǐng)求和響應(yīng)
* @param req ServletRequest對(duì)象
* @param res ServletResponse對(duì)象
* @param chain FilterChain對(duì)象,用于繼續(xù)過(guò)濾器鏈
*/
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
// 類型轉(zhuǎn)換為HTTP相關(guān)的請(qǐng)求/響應(yīng)對(duì)象
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request = (HttpServletRequest) req;
// 設(shè)置允許所有域訪問(wèn)(生產(chǎn)環(huán)境應(yīng)替換為具體域名)
response.setHeader("Access-Control-Allow-Origin", "*");
// 設(shè)置允許的HTTP方法
response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
// 設(shè)置預(yù)檢請(qǐng)求的緩存時(shí)間(1小時(shí))
response.setHeader("Access-Control-Max-Age", "3600");
// 設(shè)置允許的請(qǐng)求頭(包括自定義頭)
response.setHeader("Access-Control-Allow-Headers", "authorization, content-type, xsrf-token");
// 設(shè)置允許前端訪問(wèn)的響應(yīng)頭(暴露自定義頭)
response.addHeader("Access-Control-Expose-Headers", "xsrf-token");
// 處理OPTIONS預(yù)檢請(qǐng)求
if ("OPTIONS".equals(request.getMethod())) {
// 直接返回200狀態(tài)碼,不繼續(xù)過(guò)濾器鏈
response.setStatus(HttpServletResponse.SC_OK);
} else {
// 非OPTIONS請(qǐng)求,繼續(xù)過(guò)濾器鏈
chain.doFilter(req, res);
}
}
/**
* 過(guò)濾器初始化方法(可留空)
* @param filterConfig 過(guò)濾器配置對(duì)象
*/
@Override
public void init(FilterConfig filterConfig) {
// 初始化邏輯(如有需要)
}
/**
* 過(guò)濾器銷毀方法(可留空)
*/
@Override
public void destroy() {
// 清理資源邏輯(如有需要)
}
}2.3. Spring Security 解決方案
如果你的應(yīng)用使用了Spring Security,需要在安全配置中添加CORS支持:
/**
* Spring Security 安全配置類
* 用于配置應(yīng)用的安全策略和CORS跨域設(shè)置
*/
@Configuration // 標(biāo)記為Spring配置類
@EnableWebSecurity // 啟用Spring Security的Web安全支持
public class SecurityConfig extends WebSecurityConfigurerAdapter {
/**
* 配置HTTP安全策略
* @param http HttpSecurity對(duì)象,用于配置安全策略
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http
// 啟用CORS支持(使用下面定義的corsConfigurationSource bean)
.cors().and()
// 禁用CSRF防護(hù)(跨站請(qǐng)求偽造),因?yàn)锳PI通常使用token驗(yàn)證而非session
// 注意:如果前端與后端同域且使用session,應(yīng)該保持啟用
.csrf().disable()
// 開(kāi)始配置請(qǐng)求授權(quán)規(guī)則
.authorizeRequests()
// 允許/api/public/開(kāi)頭的URL無(wú)需認(rèn)證
.antMatchers("/api/public/**").permitAll()
// 其他所有請(qǐng)求都需要認(rèn)證
.anyRequest().authenticated();
}
/**
* 配置CORS跨域設(shè)置
* @return CorsConfigurationSource 跨域配置源
*/
@Bean
public CorsConfigurationSource corsConfigurationSource() {
// 創(chuàng)建CORS配置對(duì)象
CorsConfiguration configuration = new CorsConfiguration();
// 設(shè)置允許的源(前端地址),可以添加多個(gè)
configuration.setAllowedOrigins(Arrays.asList("http://localhost:3000"));
// 設(shè)置允許的HTTP方法
configuration.setAllowedMethods(Arrays.asList(
"GET", // 獲取資源
"POST", // 創(chuàng)建資源
"PUT", // 更新資源
"DELETE", // 刪除資源
"OPTIONS" // 預(yù)檢請(qǐng)求
));
// 設(shè)置允許的請(qǐng)求頭(*表示所有)
configuration.setAllowedHeaders(Arrays.asList("*"));
// 允許發(fā)送憑據(jù)(cookie、認(rèn)證信息等)
// 注意:當(dāng)設(shè)置為true時(shí),allowedOrigins不能為*
configuration.setAllowCredentials(true);
// 創(chuàng)建基于URL的CORS配置源
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
// 對(duì)所有URL路徑應(yīng)用上述CORS配置
source.registerCorsConfiguration("/**", configuration);
return source;
}
}2.4. 注意事項(xiàng)
生產(chǎn)環(huán)境:不要使用 * 作為允許的源,應(yīng)該明確指定允許的域名
憑證:如果前端需要發(fā)送cookie等憑證信息,需要設(shè)置 allowCredentials(true),并且不能使用 * 作為允許的源
預(yù)檢請(qǐng)求:對(duì)于復(fù)雜請(qǐng)求(如帶自定義頭的請(qǐng)求),瀏覽器會(huì)先發(fā)送OPTIONS預(yù)檢請(qǐng)求
緩存:合理設(shè)置 maxAge 可以減少預(yù)檢請(qǐng)求的次數(shù)
2.5. 測(cè)試跨域是否成功
在瀏覽器開(kāi)發(fā)者工具中檢查響應(yīng)頭是否包含:
Access-Control-Allow-Origin: http://your-frontend-domain
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Access-Control-Allow-Headers: content-type
Spring Boot應(yīng)用推薦使用全局配置或Spring Security配置的方式。
到此這篇關(guān)于Java 中的跨域問(wèn)題的文章就介紹到這了,更多相關(guān)Java 跨域內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
idea?intellij快速修復(fù)if語(yǔ)句缺少大括號(hào)的問(wèn)題
這篇文章主要介紹了idea?intellij快速修復(fù)if語(yǔ)句缺少大括號(hào)的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04
SpringBoot整合Log4j2實(shí)現(xiàn)自定義日志打印失效的原因及解決
本文給大家介紹了關(guān)于SpringBoot項(xiàng)目整合Log4j2實(shí)現(xiàn)自定義日志打印失效原因及解決辦法,主要的原因是因?yàn)镾pringBoot的logback包的存在,文中通過(guò)圖文給大家了詳細(xì)解決方法,需要的朋友可以參考下2024-01-01
springboot集成RestTemplate及常見(jiàn)的用法說(shuō)明
這篇文章主要介紹了springboot集成RestTemplate及常見(jiàn)的用法說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10
Spring中的AutowireCandidateResolver的具體使用詳解
這篇文章主要介紹了Spring中的AutowireCandidateResolver的具體使用詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04
Springboot重寫addInterceptors()方法配置攔截器實(shí)例
這篇文章主要介紹了Springboot重寫addInterceptors()方法配置攔截器實(shí)例,spring?boot拋棄了復(fù)雜的xml配置,我們可以自定義配置類(標(biāo)注@Configuration注解的類)來(lái)實(shí)現(xiàn)WebMvcConfigurer接口,并重寫addInterceptors()方法來(lái)配置攔截器,需要的朋友可以參考下2023-09-09

