背景
我們在開發(fā)過程中經常會遇到前后端分離而導致的跨域問題,導致無法獲取返回結果??缬蚓拖穹蛛x前端和后端的一道鴻溝,君在這邊,她在那邊,兩兩不能往來.
一、什么是跨域?為什么會出現(xiàn)跨域
-
定義
- 跨域(CORS)是指不同域名之間相互訪問??缬颍傅氖菫g覽器不能執(zhí)行其他網站的腳本,它是由瀏覽器的同源策略所造成的,是瀏覽器對于JavaScript所定義的安全限制策略。
當一個請求url的協(xié)議、域名、端口三者之間任意一個與當前頁面url不同即為跨域。
- 跨域(CORS)是指不同域名之間相互訪問??缬颍傅氖菫g覽器不能執(zhí)行其他網站的腳本,它是由瀏覽器的同源策略所造成的,是瀏覽器對于JavaScript所定義的安全限制策略。
-
原因
-
在前后端分離的模式下,前后端的域名是不一致的,此時就會發(fā)生跨域訪問問題。在請求的過程中我們要想回去數據一般都是post/get請求,所以…跨域問題出現(xiàn)。
-
跨域問題來源于JavaScript的同源策略,即只有 協(xié)議+主機名+端口號(如存在)相同,則允許相互訪問。也就是說JavaScript只能訪問和操作自己域下的資源,不能訪問和操作其他域下的資源。跨域問題是針對JS和ajax的,html本身沒有跨域問題,比如a標簽、script標簽、甚至form標簽(可以直接跨域發(fā)送數據并接收數據)等
-
-
什么情況會跨域
- 同一協(xié)議, 如http或https
- 同一IP地址, 如127.0.0.1
- 同一端口, 如8080
以上三個條件中有一個條件不同就會產生跨域問題。
二、Java實現(xiàn)跨域方式
2.1、返回新的 CorsFilter(全局跨域)
package org.chuancey.config;
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 GlobalCorsConfig {
@Bean
public CorsFilter corsFilter() {
//1. 添加 CORS配置信息
CorsConfiguration config = new CorsConfiguration();
// 放行哪些原始域
config.addAllowedOrigin("*");
// 是否發(fā)送 Cookie
config.setAllowCredentials(true);
// 放行哪些請求方式
config.addAllowedMethod("*");
// 放行哪些原始請求頭部信息
config.addAllowedHeader("*");
// 暴露哪些頭部信息
config.addExposedHeader("*");
//2. 添加映射路徑
UrlBasedCorsConfigurationSource corsConfigurationSource = new UrlBasedCorsConfigurationSource();
corsConfigurationSource.registerCorsConfiguration("/**",config);
//3. 返回新的CorsFilter
return new CorsFilter(corsConfigurationSource);
}
}
2.2、重寫 WebMvcConfigurer(全局跨域)
package org.chuancey.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
//放行哪些原始域
.allowedOrigins("*")
.allowedHeaders("*")
// 是否發(fā)送Cookie
.allowCredentials(true)
.allowedMethods("GET", "POST", "OPTIONS", "DELETE", "PUT", "PATCH")
.maxAge(3600);
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/**")
.addResourceLocations("classpath:/static/");
registry.addResourceHandler("swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("doc.html")
.addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}
2.3、使用注解 (局部跨域)
在控制器(類上)上使用注解 @CrossOrigin,表示該類的所有方法允許跨域。
@RestController
@CrossOrigin(origins = "*")
public class VerificationController {
}
在方法上使用注解 @CrossOrigin
@PostMapping("/check/phone")
@CrossOrigin(origins = "*")
public boolean checkPhoneNumber(@RequestBody @ApiParam VerificationPojo verification) throws BusinessException {
return false;
}
2.4、手動設置響應頭(局部跨域)
使用 HttpServletResponse 對象添加響應頭(Access-Control-Allow-Origin)來授權原始域,這里 Origin的值也可以設置為 “*”,表示全部放行。
@RequestMapping("/home")
public String home(HttpServletResponse response) {
response.addHeader("Access-Allow-Control-Origin","*");
return "home";
}
2.5、使用自定義filter實現(xiàn)跨域
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
@Slf4j
@Configuration
@WebFilter(filterName = "accessFilter", urlPatterns = "/*")
public class MyCorsFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with,content-type");
chain.doFilter(req, res);
}
public void init(FilterConfig filterConfig) {log.info("AccessFilter過濾器初始化!");}
public void destroy() {}
}
xml使自定義Filter生效方式
<!-- 跨域訪問 START-->
<filter>
<filter-name>CorsFilter</filter-name>
<filter-class>org.chuancey.filter.MyCorsFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CorsFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 跨域訪問 END -->
2.6、Spring Cloud Gateway 跨域配置
spring:
cloud:
gateway:
globalcors:
cors-configurations:
'[/**]':
# 允許跨域的源(網站域名/ip),設置*為全部
# 允許跨域請求里的head字段,設置*為全部
# 允許跨域的method, 默認為GET和OPTIONS,設置*為全部
allow-credentials: true
allowed-origins:
- "http://xb.abc.com"
- "http://sf.xx.com"
allowed-headers: "*"
allowed-methods:
- OPTIONS
- GET
- POST
- DELETE
- PUT
- PATCH
max-age: 3600
注意: 通過gateway 轉發(fā)的其他項目,不要進行配置跨域配置文章來源:http://www.zghlxwxcb.cn/news/detail-679714.html
有時即使配置了也不會起作用,這時你可以根據瀏覽器控制的錯誤輸出來查看問題,如果提示是 response 中 header 出現(xiàn)了重復的 Access-Control-* 請求頭,可以進行如下操作文章來源地址http://www.zghlxwxcb.cn/news/detail-679714.html
import java.util.ArrayList;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.NettyWriteResponseFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
@Component("corsResponseHeaderFilter")
public class CorsResponseHeaderFilter implements GlobalFilter, Ordered {
@Override
public int getOrder() {
// 指定此過濾器位于NettyWriteResponseFilter之后
// 即待處理完響應體后接著處理響應頭
return NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER + 1;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
return chain.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(new ArrayList<String>() {{
add(kv.getValue().get(0));
}});
});
return chain.filter(exchange);
}));
}
}
2.7、使用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;
}
}
2.8、繼承 HandlerInterceptorAdapter
@Component
public class CrossInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
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");
return true;
}
}
到了這里,關于【Java】Java中解決跨域問題的幾種方法(建議收藏)的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!