1. 問題を解決します。allowCredentials が true の場合、 xxxxxxx 、代わりに「allowedOriginPatterns」を使用します。
バージョン 2.3 のクロスドメイン構成は次のとおりです。
/**
* 跨域问题解决
*/
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("*")
.allowedHeaders("*")
.maxAge(3600)
.allowCredentials(true);
}
}
1.1.解決策:
Spring 公式 Web サイトにも同様の問題があります: https://github.com/spring-projects/spring-framework/issues/26111
一般的な意味は、allowedOriginPatterns メソッドが使用のために提供されているということです。元のallowCredentialsがtrueの場合、*記号を使用してallowedOriginsを照合することはできません。
/**
* 跨域问题解决
*/
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOriginPatterns("*")
.allowedMethods("*")
.allowedHeaders("*")
.maxAge(3600)
.allowCredentials(true);
}
}
実際、クロスドメイン分類を解決するには 2 つの方法があります。1 つはアノテーションを使用することで、もう 1 つは構成クラスを作成することです。
2. クロスドメインの問題を解決するいくつかの方法
2.1.クロスドメインを設定する CorsFilter メソッド
CorsFilter フィルター: Spring Boot の CORS フィルターを通じてクロスドメイン リクエストを処理するには、次のように CorsFilter Bean を定義する必要があります。
@Configuration
public class CoreFilter {
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOriginPattern("*"); // 不是 addAllowedOrigin
config.setAllowCredentials(true);
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
FilterRegistrationBean<CorsFilter> bean = new FilterRegistrationBean<>(new CorsFilter(source));
bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return new CorsFilter(source);
}
}
2.2.インターセプターはクロスドメインを実装します
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.PathMatchConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.io.Serializable;
@Configuration
@RequiredArgsConstructor
public class WebMvcConfig implements WebMvcConfigurer, Serializable {
private static final long serialVersionUID = 1L;
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
// 不是 addAllowedOrigin
.allowedOriginPatterns("*")
.allowedMethods("*")
.allowedHeaders("*")
.maxAge(3600)
.allowCredentials(true);
}
/**
* 修改访问路径
* @param configurer
*/
public void configurePathMatch(PathMatchConfigurer configurer) {
// 设置为true后,访问路径后加/ 也能正常访问 /user == /user/
configurer.setUseTrailingSlashMatch(true);
}
}
CorsFilter を使用する場合と同様に、allowCredentials が true の場合、allowedOrigins を * に設定することはできず、allowedOriginPatterns を使用する必要があります。それ以外の場合は、最終的に CorsConfiguration#validateAllowCredentials メソッドでの検証が行われます。
2.3. @CrossOrigin によるクロスドメイン実装
@CrossOrigin はクラスと個々のメソッドにアノテーションを付けることができます。@CrossOrigin アノテーションを使用して、コントローラー クラスまたはメソッドにアノテーションを付け、許可されるクロスドメイン ソース アドレス、リクエスト メソッド、ヘッダー、およびその他の属性を指定します。
注釈クラス:
コントローラー要求パスの下のすべてのメソッドは、ドメイン間で許可されます。
@CrossOrigin(origins = "http://example.com", maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController {
@RequestMapping(method = RequestMethod.GET, path = "/{id}")
public Account retrieve(@PathVariable Long id) {
// ...
}
@RequestMapping(method = RequestMethod.DELETE, path = "/{id}")
public void remove(@PathVariable Long id) {
// ...
}
}
クラスレベルで追加されます @CrossOrigin
。したがって、retrieve()
および remove()
メソッドが有効になります @CrossOrigin
。次の注釈プロパティの値を指定することで構成をカスタマイズできます: origins
、methods
、allowedHeaders
、 または 。exposedHeaders
allowCredentials
maxAge
表示方法:
注釈付きメソッドのみがドメイン間で許可されます。
@RestController
@RequestMapping("/account")
public class AccountController {
@CrossOrigin
@RequestMapping(method = RequestMethod.GET, path = "/{id}")
public Account retrieve(@PathVariable Long id) {
// ...
}
@RequestMapping(method = RequestMethod.DELETE, path = "/{id}")
public void remove(@PathVariable Long id) {
// ...
}
}
上の例では、 retrieve()
メソッドに対してのみ CORS を有効にしました。@CrossOrigin
注釈の設定を何も設定していないため、デフォルト値が使用されていることがわかります 。
- すべての原点が許可されます。
- 許可される HTTP メソッドは、
@RequestMapping
アノテーションGET
で指定されたメソッドです (この場合は )。 - プリフライト応答は 30 分間 (maxAge) キャッシュされます。
クラスとメソッドについて
@CrossOrigin(maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController {
@CrossOrigin("http://example.com")
@RequestMapping(method = RequestMethod.GET, "/{id}")
public Account retrieve(@PathVariable Long id) {
// ...
}
@RequestMapping(method = RequestMethod.DELETE, path = "/{id}")
public void remove(@PathVariable Long id) {
// ...
}
}
Spring は 2 つのアノテーションのプロパティをマージして、マージされた CORS 構成を作成します。
ここで、両方のメソッドは 秒maxAge
であり 3600
、remove()
メソッドはすべての起点を許可し、 retrieve()
メソッドは http://example.com
起点のみを許可します。
2.4.nginx
Nginx リバース プロキシ:リクエストを Nginx に転送すると、Nginx はクロスドメイン リクエストを均一に処理します。次に例を示します。
location /api/ {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, PUT, DELETE';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
proxy_pass http://localhost:8080;
}
2.5.webフィルター
@WebFilter アノテーションを使用する: このアノテーションはフィルター クラスで直接使用でき、xml ファイルで構成されたフィルターと同様に、フィルターされた URL を指定します。
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
@Component
@WebFilter(urlPatterns = "/*")
@Order(-99999)
public class CorsFilter extends HttpFilter {
private static final long serialVersionUID = 2386571986045107652L;
private static final String OPTIONS_METHOD = "OPTIONS";
@Override
protected void doFilter(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws IOException, ServletException {
String origin = req.getHeader(HttpHeaders.ORIGIN);
if (!StringUtils.isEmpty(origin)) {
// 允许客户端的域
res.addHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, origin);
// 允许客户端提交的Header
String requestHeaders = req.getHeader(HttpHeaders.ACCESS_CONTROL_REQUEST_HEADERS);
if (!StringUtils.isEmpty(requestHeaders)) {
res.addHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, requestHeaders);
}
// 允许客户端访问的Header
res.addHeader(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, "*");
// 允许客户端携带凭证信息
res.addHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
// 允许客户端请求方法
res.addHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, "GET, POST, PUT, OPTIONS, DELETE");
if (OPTIONS_METHOD.equalsIgnoreCase(req.getMethod())) {
res.setStatus(HttpServletResponse.SC_NO_CONTENT);
res.setContentType(MediaType.TEXT_HTML_VALUE);
res.setCharacterEncoding("utf-8");
res.setContentLength(0);
res.addHeader(HttpHeaders.ACCESS_CONTROL_MAX_AGE, "1800");
return;
}
}
super.doFilter(req, res, chain);
}
}