怎樣 Java 解決跨域問題

Table of Contents

引言

什么是跨域(CORS)

什么情況會跨域

解決方案

前端解決方案

后端解決方案

具體方式

一、使用Filter方式進(jìn)行設(shè)置

二、繼承 HandlerInterceptorAdapter

三、實現(xiàn) WebMvcConfigurer

四、使用Nginx配置

五、使用@CrossOrgin注解

Spring Cloud Gateway 跨域配置

引言

我們在開發(fā)過程中經(jīng)常會遇到前后端分離而導(dǎo)致的跨域問題,導(dǎo)致無法獲取返回結(jié)果。跨域就像分離前端和后端的一道鴻溝,君在這邊,她在那邊,兩兩不能往來.

什么是跨域(CORS)

跨域(CORS)是指不同域名之間相互訪問??缬?,指的是瀏覽器不能執(zhí)行其他網(wǎng)站的腳本,它是由瀏覽器的同源策略所造成的,是瀏覽器對于JavaScript所定義的安全限制策略。

什么情況會跨域

同一協(xié)議, 如http或https

同一IP地址, 如127.0.0.1

同一端口, 如8080

以上三個條件中有一個條件不同就會產(chǎn)生跨域問題。

解決方案

前端解決方案

使用JSONP方式實現(xiàn)跨域調(diào)用;

使用NodeJS服務(wù)器做為服務(wù)代理,前端發(fā)起請求到NodeJS服務(wù)器, NodeJS服務(wù)器代理轉(zhuǎn)發(fā)請求到后端服務(wù)器;

后端解決方案

nginx反向代理解決跨域

服務(wù)端設(shè)置Response Header(響應(yīng)頭部)的Access-Control-Allow-Origin

在需要跨域訪問的類和方法中設(shè)置允許跨域訪問(如Spring中使用@CrossOrigin注解);

繼承使用Spring Web的CorsFilter(適用于Spring MVC、Spring Boot)

實現(xiàn)WebMvcConfigurer接口(適用于Spring Boot)

具體方式

一、使用Filter方式進(jìn)行設(shè)置

使用Filter過濾器來過濾服務(wù)請求,向請求端設(shè)置Response Header(響應(yīng)頭部)的Access-Control-Allow-Origin屬性聲明允許跨域訪問。

@WebFilterpublicclassCorsFilterimplementsFilter{@OverridepublicvoiddoFilter(ServletRequest req, ServletResponse res, FilterChain chain)throwsIOException, ServletException{? ? ? ? ? HttpServletResponse response = (HttpServletResponse) res;? ? ? ? ? response.setHeader("Access-Control-Allow-Origin","*");? ? ? ? ? response.setHeader("Access-Control-Allow-Methods","*");? ? ? ? ? response.setHeader("Access-Control-Max-Age","3600");? ? ? ? ? response.setHeader("Access-Control-Allow-Headers","*");? ? ? ? response.setHeader("Access-Control-Allow-Credentials","true");? ? ? ? chain.doFilter(req, res);? ? ? }? }復(fù)制代碼

二、繼承 HandlerInterceptorAdapter

@ComponentpublicclassCrossInterceptorextendsHandlerInterceptorAdapter{@OverridepublicbooleanpreHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throwsException{? ? ? ? response.setHeader("Access-Control-Allow-Origin","*");? ? ? ? response.setHeader("Access-Control-Allow-Methods","GET, POST, PUT, DELETE, OPTIONS");? ? ? ? response.setHeader("Access-Control-Max-Age","3600");? ? ? ? response.setHeader("Access-Control-Allow-Headers","*");? ? ? ? response.setHeader("Access-Control-Allow-Credentials","true");returntrue;? ? }}復(fù)制代碼

三、實現(xiàn) WebMvcConfigurer

@Configuration@SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection")publicclassAppConfigimplementsWebMvcConfigurer{@OverridepublicvoidaddCorsMappings(CorsRegistry registry){? ? ? ? registry.addMapping("/**")// 攔截所有的請求.allowedOrigins("http://www.abc.com")// 可跨域的域名,可以為 *.allowCredentials(true)? ? ? ? ? ? ? ? .allowedMethods("*")// 允許跨域的方法,可以單獨配置.allowedHeaders("*");// 允許跨域的請求頭,可以單獨配置}}復(fù)制代碼

四、使用Nginx配置

location / {? add_header Access-Control-Allow-Origin *;? add_header Access-Control-Allow-Headers X-Requested-With;? add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;? if ($request_method = 'OPTIONS') {? ? return 204;? }}復(fù)制代碼

五、使用@CrossOrgin注解

如果只是想部分接口跨域,且不想使用配置來管理的話,可以使用這種方式

在Controller使用

@CrossOrigin@RestController@RequestMapping("/user")public class UserController {@GetMapping("/{id}")public User get(@PathVariable Long id) {}@DeleteMapping("/{id}")public void remove(@PathVariable Long id) {}}復(fù)制代碼

在具體接口上使用

@RestController@RequestMapping("/user")public class UserController {@CrossOrigin@GetMapping("/{id}")public User get(@PathVariable Long id) {}@DeleteMapping("/{id}")public void remove(@PathVariable Long id) {}}復(fù)制代碼

Spring Cloud Gateway 跨域配置

spring:cloud:gateway:globalcors:cors-configurations:'[/**]':# 允許跨域的源(網(wǎng)站域名/ip),設(shè)置*為全部# 允許跨域請求里的head字段,設(shè)置*為全部# 允許跨域的method, 默認(rèn)為GET和OPTIONS,設(shè)置*為全部allow-credentials:trueallowed-origins:-"http://xb.abc.com"-"http://sf.xx.com"allowed-headers:"*"allowed-methods:-OPTIONS-GET-POST-DELETE-PUT-PATCHmax-age:3600復(fù)制代碼

注意:通過gateway轉(zhuǎn)發(fā)的其他項目,不要進(jìn)行配置跨域配置

有時即使配置了也不會起作用,這時你可以根據(jù)瀏覽器控制的錯誤輸出來查看問題,如果提示是response中 header 出現(xiàn)了重復(fù)的Access-Control-*請求頭,可以進(jìn)行如下操作

importjava.util.ArrayList;

importorg.springframework.cloud.gateway.filter.GatewayFilterChain;

importorg.springframework.cloud.gateway.filter.GlobalFilter;

importorg.springframework.cloud.gateway.filter.NettyWriteResponseFilter;

importorg.springframework.core.Ordered;

importorg.springframework.http.HttpHeaders;

importorg.springframework.stereotype.Component;importorg.springframework.web.server.ServerWebExchange;

importreactor.core.publisher.Mono;@Component("corsResponseHeaderFilter")publicclassCorsResponseHeaderFilterimplementsGlobalFilter,Ordered{@OverridepublicintgetOrder()

{// 指定此過濾器位于NettyWriteResponseFilter之后// 即待處理完響應(yīng)體后接著處理響應(yīng)頭returnNettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER +1;? }

@OverridepublicMonofilter(ServerWebExchange exchange, GatewayFilterChain chain){returnchain.filter(exchange).then(Mono.defer(() -> {? ? ? exchange.getResponse().getHeaders().entrySet().stream()? ? ? ? ? .filter(kv -> (kv.getValue() !=null&& kv.getValue().size() >1))? ? ? ? ? .filter(kv -> (? ? ? ? ? ? ? kv.getKey().equals(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN)? ? ? ? ? ? ? ? ? || kv.getKey().equals(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS)? ? ? ? ? ? ? ? ? || kv.getKey().equals(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS)? ? ? ? ? ? ? ? ? || kv.getKey().equals(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS)? ? ? ? ? ? ? ? ? || kv.getKey().equals(HttpHeaders.ACCESS_CONTROL_MAX_AGE)))? ? ? ? ? .forEach(kv -> {? ? ? ? ? ? kv.setValue(newArrayList() {{? ? ? ? ? ? ? add(kv.getValue().get(0));? ? ? ? ? ? }});? ? ? ? ? });returnchain.filter(exchange);? ? }));? }}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容