最近公司開始推行先後端分離的架構,因而不可避免的引入了跨域的問題,跨域的概念能夠參考大佬的博客,這裏就再也不贅述了。
做爲Java最流行框架之一的Spring其實已經幫咱們寫好了不少代碼,咱們只須要簡單配置一下便可,固然下面會提到仍是有一些不如人意的地方。
PS:本文沒有使用SpringBoot
html
在SpringMVC的配置文件中添加以下配置便可前端
<mvc:cors> <mvc:mapping path="/**" allow-credentials="true" allowed-methods="*" allowed-headers="*" allowed-origins="*"/> </mvc:cors>
註解能夠寫在類上也能夠寫在方法上java
@CrossOrigin(maxAge = 3600) @RestController @RequestMapping("/account") public class AccountController { @CrossOrigin("http://domain2.com") @RequestMapping("/{id}") public Account retrieve(@PathVariable Long id) { // ... } @RequestMapping(method = RequestMethod.DELETE, path = "/{id}") public void remove(@PathVariable Long id) { // ... } }
通常咱們使用的都是全局的配置,而SpringMVC把跨域處理的攔截器放到了最後一個,那麼咱們權限過濾的攔截器就是排在了跨域處理以前,若是一個請求是無權限的,那麼被攔截返回以後因爲沒有跨域處理,在前端展現的就是跨域失敗的提示。一樣的,你全部的攔截器的攔截返回都是跨域失敗的提示,這顯然是不合理的。web
SpringMVC還支持基於filter的跨域處理,因爲filter的位置是在interceptor以前的,因此能夠完美解決上述問題。官方給出的一個例子以下:spring
@Configuration public class MyConfiguration { @Bean public FilterRegistrationBean corsFilter() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration config = new CorsConfiguration(); config.setAllowCredentials(true); config.addAllowedOrigin("http://domain1.com"); config.addAllowedHeader("*"); config.addAllowedMethod("*"); source.registerCorsConfiguration("/**", config); FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source)); bean.setOrder(0); return bean; } }
方法一有個比較坑的地方就是FilterRegistrationBean這個類只有SpringBoot中才有,那咱們項目沒有用SpringBoot咋辦,下邊是常規配置的方法:後端
<!-- 這個配置須要放到Spring的配置文件中,不能放到SpringMVC的配置文件,由於SpringMVC的加載是基於Servlet,它是晚於Filter的 --> <bean id="corsFilter" class="org.springframework.web.filter.CorsFilter"> <constructor-arg name="configSource"> <bean class="org.springframework.web.cors.UrlBasedCorsConfigurationSource"> <property name="corsConfigurations"> <map> <entry key="/**"> <bean class="org.springframework.web.cors.CorsConfiguration"> <property name="allowCredentials" value="true"/> <property name="allowedMethods"> <list> <value>GET</value> <value>POST</value> <value>HEAD</value> </list> </property> <property name="allowedHeaders" value="*"/> <property name="allowedOrigins" value="*"/> </bean> </entry> </map> </property> </bean> </constructor-arg> </bean>
因爲CorsFilter跟一般的Filter不同,Spring對其作了不少改造,因此加載的方式要使用DelegatingFilterProxy,經過Spring的方式把它放到容器中跨域
<!-- web.xml --> <filter> <filter-name>myCorsFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <init-param> <param-name>targetBeanName</param-name> <param-value>corsFilter</param-value> </init-param> </filter> <filter-mapping> <filter-name>myCorsFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
除了使用Spring提供的方法,你也能夠本身編寫跨域的處理,由於跨域的處理其實就是在響應頭裏加一些東西架構
public class CorsInterceptor extends HandlerInterceptorAdapter { //@Setter是lombok的註解,等價於setter方法,下同 @Setter private String allowCredentials; @Setter private String allowedMethods; @Setter private String allowedHeaders; @Setter private String allowedOrigins; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { log.info("Adding Access Control Response Headers"); if (CorsUtils.isCorsRequest(request)) { ServletServerHttpRequest wrapRequest = new ServletServerHttpRequest(request); if(CorsConfiguration.ALL.equals(allowedOrigins)) { response.setHeader("Access-Control-Allow-Origin", wrapRequest.getHeaders().getOrigin()); } else { response.setHeader("Access-Control-Allow-Origin", allowedOrigins); } response.setHeader("Access-Control-Allow-Credentials", allowCredentials); response.setHeader("Access-Control-Allow-Methods", allowedMethods); response.setHeader("Access-Control-Allow-Headers", allowedHeaders); } return true; } }
SpringMVC配置mvc
<mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/**/*.do"/> <bean class="com.fingard.gardpay.websys.web.interceptor.CorsInterceptor"> <property name="allowCredentials" value="true"/> <property name="allowedHeaders" value="*"/> <property name="allowedMethods" value="GET,POST,HEAD,OPTIONS"/> <property name="allowedOrigins" value="*"/> </bean> </mvc:interceptor> </mvc:interceptors>