The applications we are developing now usually transmit data from the foreground and background, or when our application server needs to provide data for multiple applications, it should be noted that cross-domain is a security policy set by browsers, that is, if our services are not provided for browsers to use. There is no need to consider cross-domain issues. Of course, if we are developing web applications, we need to focus on cross-domain issues.
Browsers process requests for different domain names by sending a request for options, which simply compares the server's response header with our request header. If cross-domain is allowed in the response header, real data requests will be sent in the past.
Requests for options in servlet containers are not distributed by default at our business controller layer, so there are two ways to handle cross-domain requests
-
Use filter
The filter is the web container layer, that is, the servlet container to filter requests, so we can use the filter to process the options requests before the servlet container processes them. First, we need to implement the filter interface of the servlet, and then process the requests inside, such as:
package uc.meven.test2.filter; 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.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; @Component public class MyCORSFilter implements Filter{ private static final Logger log = LoggerFactory.getLogger(MyCORSFilter.class); @Override public void destroy() { // TODO Auto-generated method stub } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletResponse response = (HttpServletResponse) servletResponse; // String origin = (String) servletRequest.getRemoteHost()+":"+servletRequest.getRemotePort(); 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,Authorization,x-csrf-token"); response.setHeader("Access-Control-Allow-Credentials","true"); filterChain.doFilter(servletRequest, servletResponse); } @Override public void init(FilterConfig arg0) throws ServletException { // TODO Auto-generated method stub } }
Then add our custom filter to the web container, that is, in web.xml
<filter> <filter-name>cors</filter-name> <! - Location of the fi lt er class defined - > <filter-class>uc.meven.test2.filter.MyCORSFilter</filter-class> </filter> <filter-mapping> <! -- Only a few requests are fi lt ered, and all requests under / ajax can be cross-domain - >. <filter-name>cors</filter-name> <url-pattern>/ajax/*</url-pattern> </filter-mapping>
-
In addition, we can also not process cross-domain requests in the servlet container layer, and can float up to our spring layer. At this time, we need to open the configuration of servlets for options requests that are not distributed, and add it to web.xml.
<init-param> <param-name>dispatchOptionsRequest</param-name> <param-value>true</param-value> </init-param>
Then we can add an interceptor request interceptor to intercept all requests and set the allowable cross-domain. At this time, we need to implement spring's Hadler Interceptor interceptor interface to process options requests.
package uc.meven.test2.interceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.HttpHeaders; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; public class AccessControllerInterceptor implements HandlerInterceptor { private static final Logger log = LoggerFactory.getLogger(AccessControllerInterceptor.class); @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { log.info("enter interceptor==========="); // TODO Auto-generated method stub final String uri = request.getRequestURI(); final String origin = request.getHeader(HttpHeaders.ORIGIN); response.setHeader("Access-Control-Allow-Origin", origin); response.setHeader("Access-Control-Allow-Credentials", "true"); response.setHeader("Access-Control-Allow-Headers", "Content-Type, accept, apikey, sign, timestamp"); response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE"); log.info("request uri:{}, origin:{}, access success", uri, origin); // If it's an option request, return it directly, and if it's not, go to the business layer for processing. return !"options".equalsIgnoreCase(request.getMethod()); } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { // TODO Auto-generated method stub } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // TODO Auto-generated method stub } }
Next we need to enable our interceptor in the configuration of spring MVC
<mvc:interceptors> <bean class="uc.meven.test2.interceptor.AccessControllerInterceptor" /> </mvc:interceptors>
Although we can use the second method to achieve cross-request processing, according to the concept of software hierarchy, we should do this at the servlet container layer, not polluting our business layer code, so we recommend the first method.