


Sample code analysis of spring MVC cors cross-domain implementation source code
This article mainly introduces spring MVC cors cross-domain implementation source code parsing. It has a very good reference value. Let’s take a look at it with the editor.
Explanation of terms: Cross-Origin Resource Sharing
To put it simply, as long as the protocol, IP, Any difference in the http method is cross-domain.
spring MVC has added cross-domain support since 4.2.
For the specific definition of cross-domain, please go to mozilla to view
Use cases
There are 3 cross-domain uses in spring mvc One way:
Configure CorsFilter in web.xml
<filter> <filter-name>cors</filter-name> <filter-class>org.springframework.web.filter.CorsFilter</filter-class> </filter> <filter-mapping> <filter-name>cors</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
Configure in xml
// 简单配置,未配置的均使用默认值,就是全面放开 <mvc:cors> <mvc:mapping path="/**" /> </mvc:cors> // 这是一个全量配置 <mvc:cors> <mvc:mapping path="/api/**" allowed-origins="http://domain1.com, http://www.php.cn/" allowed-methods="GET, PUT" allowed-headers="header1, header2, header3" exposed-headers="header1, header2" allow-credentials="false" max-age="123" /> <mvc:mapping path="/resources/**" allowed-origins="http://domain1.com" /> </mvc:cors>
Use annotations
@CrossOrigin(maxAge = 3600) @RestController @RequestMapping("/account") public class AccountController { @CrossOrigin("http://domain2.com") @RequestMapping("/{id}") public Account retrieve(@PathVariable Long id) { // ... } }
Involving concepts
CorsConfiguration is a pojo that specifically encapsulates cross-domain configuration information
Container for mapping CorsConfigurationSource request and cross-domain configuration information
CorsProcessor class for specific cross-domain operations
NUOGAN cross-domain configuration information initialization class
NUOGAN cross-domain Adapter
Involved java classes :
Pojo that encapsulates information
CorsConfiguration
Container that stores request and cross-domain configuration information
CorsConfigurationSource, UrlBasedCorsConfigurationSource
Specific processing class
CorsProcessor, DefaultCorsProcessor
CorsUtils
Adapter that implements the OncePerRequestFilter interface
CorsFilter
Verifies whether the request is cors, and encapsulates the corresponding Adapter
AbstractHandlerMapping, including Internal classes PreFlightHandler, CorsInterceptor
Read CrossOrigin annotation information
AbstractHandlerMethodMapping, RequestMappingHandlerMapping
Read cross-domain configuration information from xml files
CorsBeanDefinitionParser
Cross-domain registration auxiliary class
MvcNamespaceUtils
debug analysis
To understand the code, we need to first understand the pojo that encapsulates cross-domain information--CorsConfiguration
Here is a very simple pojo. In addition to several cross-domain corresponding attributes, there are only combine, checkOrigin, checkHttpMethod, checkHeaders.
Attributes are used in combination with multiple values.
// CorsConfiguration public static final String ALL = "*"; // 允许的请求源 private List<String> allowedOrigins; // 允许的http方法 private List<String> allowedMethods; // 允许的请求头 private List<String> allowedHeaders; // 返回的响应头 private List<String> exposedHeaders; // 是否允许携带cookies private Boolean allowCredentials; // 预请求的存活有效期 private Long maxAge;
combine is to merge cross-domain information.
The three check methods are to check whether the information in the request is included in the allowed range.
Configuration initialization
Parse the configuration file through CorsBeanDefinitionParser when the system starts;
When loading RequestMappingHandlerMapping, through the afterProperties of InitializingBean The hook calls initCorsConfiguration to initialize the annotation information;
Configuration file initialization
Put a breakpoint in the parse method of the CorsBeanDefinitionParser class.
The call stack of CorsBeanDefinitionParser
You can see the analysis here through the code
Cross-domain The configuration of information can define multiple mapping relationships in units of paths.
If not defined during parsing, the default settings will be used
// CorsBeanDefinitionParser if (mappings.isEmpty()) { // 最简配置时的默认设置 CorsConfiguration config = new CorsConfiguration(); config.setAllowedOrigins(DEFAULT_ALLOWED_ORIGINS); config.setAllowedMethods(DEFAULT_ALLOWED_METHODS); config.setAllowedHeaders(DEFAULT_ALLOWED_HEADERS); config.setAllowCredentials(DEFAULT_ALLOW_CREDENTIALS); config.setMaxAge(DEFAULT_MAX_AGE); corsConfigurations.put("/**", config); }else { // 单个mapping的处理 for (Element mapping : mappings) { CorsConfiguration config = new CorsConfiguration(); if (mapping.hasAttribute("allowed-origins")) { String[] allowedOrigins = StringUtils.tokenizeToStringArray(mapping.getAttribute("allowed-origins"), ","); config.setAllowedOrigins(Arrays.asList(allowedOrigins)); } // ... }
After parsing is completed, register through MvcNamespaceUtils.registerCorsConfiguratoions
This What is being followed is the unified process of spring bean container management, which is now converted into BeanDefinition and then instantiated.
// MvcNamespaceUtils public static RuntimeBeanReference registerCorsConfigurations(Map<String, CorsConfiguration> corsConfigurations, ParserContext parserContext, Object source) { if (!parserContext.getRegistry().containsBeanDefinition(CORS_CONFIGURATION_BEAN_NAME)) { RootBeanDefinition corsConfigurationsDef = new RootBeanDefinition(LinkedHashMap.class); corsConfigurationsDef.setSource(source); corsConfigurationsDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); if (corsConfigurations != null) { corsConfigurationsDef.getConstructorArgumentValues().addIndexedArgumentValue(0, corsConfigurations); } parserContext.getReaderContext().getRegistry().registerBeanDefinition(CORS_CONFIGURATION_BEAN_NAME, corsConfigurationsDef); parserContext.registerComponent(new BeanComponentDefinition(corsConfigurationsDef, CORS_CONFIGURATION_BEAN_NAME)); } else if (corsConfigurations != null) { BeanDefinition corsConfigurationsDef = parserContext.getRegistry().getBeanDefinition(CORS_CONFIGURATION_BEAN_NAME); corsConfigurationsDef.getConstructorArgumentValues().addIndexedArgumentValue(0, corsConfigurations); } return new RuntimeBeanReference(CORS_CONFIGURATION_BEAN_NAME); }
Annotation initialization
Scan the method annotated with CrossOrigin in the initCorsConfiguration of RequestMappingHandlerMapping and extract the information.
// RequestMappingHandlerMapping @Override protected CorsConfiguration initCorsConfiguration(Object handler, Method method, RequestMappingInfo mappingInfo) { HandlerMethod handlerMethod = createHandlerMethod(handler, method); CrossOrigin typeAnnotation = AnnotatedElementUtils.findMergedAnnotation(handlerMethod.getBeanType(), CrossOrigin.class); CrossOrigin methodAnnotation = AnnotatedElementUtils.findMergedAnnotation(method, CrossOrigin.class); if (typeAnnotation == null && methodAnnotation == null) { return null; } CorsConfiguration config = new CorsConfiguration(); updateCorsConfig(config, typeAnnotation); updateCorsConfig(config, methodAnnotation); // ... 设置默认值 return config; }
Cross-domain request processing
HandlerMapping After processing the search processor normally, check whether it is a cross-domain request in AbstractHandlerMapping.getHandler. If it is processed in two ways:- If it is a pre-request, The processor is replaced with the internal class PreFlightHandler
- If it is a normal request, add the CorsInterceptor interceptor
拿到处理器后,通过请求头是否包含Origin判断是否跨域,如果是跨域,通过UrlBasedCorsConfigurationSource获取跨域配置信息,并委托getCorsHandlerExecutionChain处理
UrlBasedCorsConfigurationSource是CorsConfigurationSource的实现,从类名就可以猜出这边request与CorsConfiguration的映射是基于url的。getCorsConfiguration中提取request中的url后,逐一验证配置是否匹配url。
// UrlBasedCorsConfigurationSource public CorsConfiguration getCorsConfiguration(HttpServletRequest request) { String lookupPath = this.urlPathHelper.getLookupPathForRequest(request); for(Map.Entry<String, CorsConfiguration> entry : this.corsConfigurations.entrySet()) { if (this.pathMatcher.match(entry.getKey(), lookupPath)) { return entry.getValue(); } } return null; } // AbstractHandlerMapping public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { Object handler = getHandlerInternal(request); // ... HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request); if (CorsUtils.isCorsRequest(request)) { CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request); CorsConfiguration handlerConfig = getCorsConfiguration(handler, request); CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig); executionChain = getCorsHandlerExecutionChain(request, executionChain, config); } return executionChain; } // HttpHeaders public static final String ORIGIN = "Origin"; // CorsUtils public static boolean isCorsRequest(HttpServletRequest request) { return (request.getHeader(HttpHeaders.ORIGIN) != null); }
通过请求头的http方法是否options判断是否预请求,如果是使用PreFlightRequest替换处理器;如果是普通请求,添加一个拦截器CorsInterceptor。
PreFlightRequest是CorsProcessor对于HttpRequestHandler的一个适配器。这样HandlerAdapter直接使用HttpRequestHandlerAdapter处理。
CorsInterceptor 是CorsProcessor对于HnalderInterceptorAdapter的适配器。
// AbstractHandlerMapping protected HandlerExecutionChain getCorsHandlerExecutionChain(HttpServletRequest request, HandlerExecutionChain chain, CorsConfiguration config) { if (CorsUtils.isPreFlightRequest(request)) { HandlerInterceptor[] interceptors = chain.getInterceptors(); chain = new HandlerExecutionChain(new PreFlightHandler(config), interceptors); } else { chain.addInterceptor(new CorsInterceptor(config)); } return chain; } private class PreFlightHandler implements HttpRequestHandler { private final CorsConfiguration config; public PreFlightHandler(CorsConfiguration config) { this.config = config; } @Override public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws IOException { corsProcessor.processRequest(this.config, request, response); } } private class CorsInterceptor extends HandlerInterceptorAdapter { private final CorsConfiguration config; public CorsInterceptor(CorsConfiguration config) { this.config = config; } @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return corsProcessor.processRequest(this.config, request, response); } } // CorsUtils public static boolean isPreFlightRequest(HttpServletRequest request) { return (isCorsRequest(request) && request.getMethod().equals(HttpMethod.OPTIONS.name()) && request.getHeader(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD) != null); }
The above is the detailed content of Sample code analysis of spring MVC cors cross-domain implementation source code. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics



In 2023, AI technology has become a hot topic and has a huge impact on various industries, especially in the programming field. People are increasingly aware of the importance of AI technology, and the Spring community is no exception. With the continuous advancement of GenAI (General Artificial Intelligence) technology, it has become crucial and urgent to simplify the creation of applications with AI functions. Against this background, "SpringAI" emerged, aiming to simplify the process of developing AI functional applications, making it simple and intuitive and avoiding unnecessary complexity. Through "SpringAI", developers can more easily build applications with AI functions, making them easier to use and operate.

As an industry leader, Spring+AI provides leading solutions for various industries through its powerful, flexible API and advanced functions. In this topic, we will delve into the application examples of Spring+AI in various fields. Each case will show how Spring+AI meets specific needs, achieves goals, and extends these LESSONSLEARNED to a wider range of applications. I hope this topic can inspire you to understand and utilize the infinite possibilities of Spring+AI more deeply. The Spring framework has a history of more than 20 years in the field of software development, and it has been 10 years since the Spring Boot 1.0 version was released. Now, no one can dispute that Spring

How to implement spring programmatic transactions: 1. Use TransactionTemplate; 2. Use TransactionCallback and TransactionCallbackWithoutResult; 3. Use Transactional annotations; 4. Use TransactionTemplate in combination with @Transactional; 5. Customize the transaction manager.

How to set the transaction isolation level in Spring: 1. Use the @Transactional annotation; 2. Set it in the Spring configuration file; 3. Use PlatformTransactionManager; 4. Set it in the Java configuration class. Detailed introduction: 1. Use the @Transactional annotation, add the @Transactional annotation to the class or method that requires transaction management, and set the isolation level in the attribute; 2. In the Spring configuration file, etc.

Introduction In today's rapidly evolving digital world, it is crucial to build robust, flexible and maintainable WEB applications. The PHPmvc architecture provides an ideal solution to achieve this goal. MVC (Model-View-Controller) is a widely used design pattern that separates various aspects of an application into independent components. The foundation of MVC architecture The core principle of MVC architecture is separation of concerns: Model: encapsulates the data and business logic of the application. View: Responsible for presenting data and handling user interaction. Controller: Coordinates the interaction between models and views, manages user requests and business logic. PHPMVC Architecture The phpMVC architecture follows the traditional MVC pattern, but also introduces language-specific features. The following is PHPMVC

Spring is an open source framework that provides many annotations to simplify and enhance Java development. This article will explain commonly used Spring annotations in detail and provide specific code examples. @Autowired: Autowired @Autowired annotation can be used to automatically wire beans in the Spring container. When we use the @Autowired annotation where dependencies are required, Spring will find matching beans in the container and automatically inject them. The sample code is as follows: @Auto

JUnit is a widely used Java unit testing framework in Spring projects and can be applied by following steps: Add JUnit dependency: org.junit.jupiterjunit-jupiter5.8.1test Write test cases: Use @ExtendWith(SpringExtension.class) to enable extension, use @Autowired inject beans, use @BeforeEach and @AfterEach to prepare and clean, and mark test methods with @Test.

The MVC architecture (Model-View-Controller) is one of the most popular patterns in PHP development because it provides a clear structure for organizing code and simplifying the development of WEB applications. While basic MVC principles are sufficient for most web applications, it has some limitations for applications that need to handle complex data or implement advanced functionality. Separating the model layer Separating the model layer is a common technique in advanced MVC architecture. It involves breaking down a model class into smaller subclasses, each focusing on a specific functionality. For example, for an e-commerce application, you might break down the main model class into an order model, a product model, and a customer model. This separation helps improve code maintainability and reusability. Use dependency injection
