原文地址:http://dontpanic.42.nl/2015/04/cors-with-spring-mvc.html

CORS with Spring MVC

 

In this blog post I will explain how to implement Cross-Origin Resource Sharing (CORS) on a Spring MVC backend.

CORS is a W3C spec that allows cross-domain communication from the browser. Whenever a request is made from http://www.domaina.com to http://www.domainb.com, or even from http://localhost:8000 to http://localhost:9000, you will need to implement CORS on your backend.

To allow CORS we need to add the following headers to all Spring MVC responses:


Access-Control-Allow-Credentials: true Access-Control-Allow-Origin: http://localhost:9000 Access-Control-Allow-Methods: GET, OPTIONS, POST, PUT, DELETE Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept Access-Control-Max-Age: 3600

The easiest way to do this is by creating an interceptor:


public class CorsInterceptor extends HandlerInterceptorAdapter { public static final String CREDENTIALS_NAME = "Access-Control-Allow-Credentials";
public static final String ORIGIN_NAME = "Access-Control-Allow-Origin";
public static final String METHODS_NAME = "Access-Control-Allow-Methods";
public static final String HEADERS_NAME = "Access-Control-Allow-Headers";
public static final String MAX_AGE_NAME = "Access-Control-Max-Age"; @Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
response.setHeader(CREDENTIALS_NAME, "true");
response.setHeader(ORIGIN_NAME, "http://localhost:9000");
response.setHeader(METHODS_NAME, "GET, OPTIONS, POST, PUT, DELETE");
response.setHeader(HEADERS_NAME, "Origin, X-Requested-With, Content-Type, Accept");
response.setHeader(MAX_AGE_NAME, "3600");
return true;
} }

Then we register this interceptor in our web configuration:

public class WebMvcConfig extends WebMvcConfigurerAdapter {

    @Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new CorsInterceptor());
} ... }

Now all GET requests will be handled correctly.

Modification requests

Whenever we do a modification request (POST, PUT, DELETE), our browser will first send a 'preflight' OPTIONS request. This is an extra security check to see if you can modify data. Because Spring MVC ignores OPTIONS requests by default, we will not get a CORS compliant response. We can overwrite this configuration as follows:

When using a Java configuration, in the DispatcherServletInitializer:


@Override
protected void customizeRegistration(Dynamic registration) {
registration.setInitParameter("dispatchOptionsRequest", "true");
super.customizeRegistration(registration);
}

Or in the web.xml:


<servlet>
<servlet-name>yourServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>dispatchOptionsRequest</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

Now we can write a simple handler for OPTIONS requests:

@Controller
public class OptionsController { @RequestMapping(method = RequestMethod.OPTIONS)
public ResponseEntity handle() {
return new ResponseEntity(HttpStatus.NO_CONTENT);
} }

This controller handles all OPTIONS requests, sending back a NO_CONTENT response with the desired CORS headers due to our interceptor. Now that OPTIONS respond correctly, the PUT, POST and DELETE will also work correctly.

Congratulations, you now have a CORS compliant Spring MVC backend :)

Multiple origins

Sometimes you have a backend service that is used by multiple applications and thus serves multiple origins. With some minor code changes we can implement this feature:


public class CorsInterceptor extends HandlerInterceptorAdapter { private static final Logger LOGGER = LoggerFactory.getLogger(CorsInterceptor.class); public static final String REQUEST_ORIGIN_NAME = "Origin"; public static final String CREDENTIALS_NAME = "Access-Control-Allow-Credentials";
public static final String ORIGIN_NAME = "Access-Control-Allow-Origin";
public static final String METHODS_NAME = "Access-Control-Allow-Methods";
public static final String HEADERS_NAME = "Access-Control-Allow-Headers";
public static final String MAX_AGE_NAME = "Access-Control-Max-Age"; private final List<String> origins; public CorsInterceptor(String origins) {
this.origins = Arrays.asList(origins.trim().split("( )*,( )*"));
} @Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
response.setHeader(CREDENTIALS_NAME, "true");
response.setHeader(METHODS_NAME, "GET, OPTIONS, POST, PUT, DELETE");
response.setHeader(HEADERS_NAME, "Origin, X-Requested-With, Content-Type, Accept");
response.setHeader(MAX_AGE_NAME, "3600"); String origin = request.getHeader(REQUEST_ORIGIN_NAME);
if (origins.contains(origin)) {
response.setHeader(ORIGIN_NAME, origin);
return true; // Proceed
} else {
LOGGER.warn("Attempted access from non-allowed origin: {}", origin);
// Include an origin to provide a clear browser error
response.setHeader(ORIGIN_NAME, origins.iterator().next());
return false; // No need to find handler
}
} }

All we do now is checking if our request origin is in the list of allowed origins and echo it back into the response. Thus if somebody makes a request from 'domain-a.com' we return back that same 'domain-a.com' as allowed origin, while for 'domain-b.com' we return 'domain-b.com'.

Because the list of allowed origins is provided as string, we can simply define our origins in a properties file:

cors.origins=http://www.domain-a.com,http://www.domain-b.com

CORS with Spring MVC--转的更多相关文章

  1. enable cors in spring mvc with swagger

    a. In controller add @CrossOrigin(origins = "http://localhost:8080") b. In mvc-servlet.xml ...

  2. 从零开始学 Java - Spring MVC 实现跨域资源 CORS 请求

    论职业的重要性 问:为什么所有家长都希望自己的孩子成为公务员? 答:体面.有权.有钱又悠闲. 问:为什么所有家长都希望自己的孩子成为律师或医生? 答:体面.有钱.有技能. 问:为什么所有家长都不怎么知 ...

  3. spring MVC cors跨域实现源码解析

    # spring MVC cors跨域实现源码解析 > 名词解释:跨域资源共享(Cross-Origin Resource Sharing) 简单说就是只要协议.IP.http方法任意一个不同就 ...

  4. Java - Spring MVC 实现跨域资源 CORS 请求

    拦截器设置响应头 这种方式原理就是利用拦截器在方法执行前,我们增加请求的响应头,用来支持跨域请求.这种方案是可行的,大部分都是采用这种方案.我当时也是打算采用这种方案,直到我发现原来 Spring 框 ...

  5. Spring MVC使用Cors实现跨域

    在开发APP过程中,APP调用后端接口有跨域的问题,只要在spring-mvc.xml 文件中加入下面的配置即可: <!-- 解决API接口跨域问题配置 Spring MVC 版本必须是 4.2 ...

  6. Spring MVC 4.2 CORS 跨域访问

    跨站 HTTP 请求(Cross-site HTTP request)是指发起请求的资源所在域不同于该请求所指向资源所在的域的 HTTP 请求.比如说,域名A(http://domaina.examp ...

  7. Spring MVC 实现跨域资源 CORS 请求

    说到 AJAX 跨域,很多人最先想到的是 JSONP.的确,JSONP 我们已经十分熟悉,也使用了多年,从本质上讲,JSONP 的原理是给页面注入一个 <script>,把远程 JavaS ...

  8. Spring MVC配置CORS(解决跨域请求)

    1. CORS 简介 同源策略(same origin policy)是浏览器安全的基石.在同源策略的限制下,非同源的网站之间不能发送 ajax 请求的. 为了解决这个问题,w3c 提出了跨源资源共享 ...

  9. Spring MVC 后端接口支持跨域CORS调用

    Spring MVC 从4.2版本开始增加了对CORS的支持,可以全局配置,也可以对类或方法配置:可以通过Java代码,也可以通过xml配置方式. 对于低版本的Spring MVC 可以通过Filte ...

随机推荐

  1. You Probably Don’t Need a Message Queue

    原文地址 I’m a minimalist, and I don’t like to complicate software too early and unnecessarily. And addi ...

  2. caioj 1157 线性筛选素数

    注意这道题开得非常大,有2*1e7 自己可以养成一种习惯,如果数据是很容易的话,可以自己手动输入极限数据来测试自己的程序 #include<cstdio> #include<algo ...

  3. pandas学习笔记 - 常见的数据处理方式

    1.缺失值处理 - 拉格朗日插值法 input_file数据文件内容(存在部分缺失值): from scipy.interpolate import lagrange import pandas as ...

  4. MongoDB查询、索引和聚合

    初始化mongodb数据库 > use deng switched to db deng > db.createCollection("jingdong") #无參数 ...

  5. Lambert/Diffuse 光照模型

    Lambert/Diffuse光照模型的特点:各向同性,即与观察的方向无关,反射光只与入射光和入射角度相关. 1.光源垂直照射平面 如图,设入射光量为Ф, 平面面积为A, 则可以认为平面上每一点获取的 ...

  6. sklearn.preprocessing OneHotEncoder——仅仅是数值型字段才可以,如果是字符类型字段则不能直接搞定

    >>> from sklearn.preprocessing import OneHotEncoder >>> enc = OneHotEncoder() > ...

  7. 网络流Dinic算法模板 POJ1273

    这就是以后我的板子啦~~~ #include <queue> #include <cstdio> #include <cstring> #include <a ...

  8. java9新特性-6-多版本兼容jar包

    1.官方Feature 238: Multi-Release JAR Files 2.使用说明 当一个新版本的Java出现的时候,你的库用户要花费数年时间才会切换到这个新的版本.这就意味着库得去向后兼 ...

  9. java根据模板导出PDF(利用itext)

    一.制作模板     1.下载Adobe Acrobat 9 Pro软件(pdf编辑器),制作模板必须使用该工具. 2.下载itextpdf-5.5.5.jar.itext-asian-5.2.0.j ...

  10. 增强for循环的使用详解及代码

    首先说一下他的语法结构: for(数据类型 变量 :集合){ //这里写要遍历的元素,或者所需要的代码即可//如果集合中存放的是对象,可以获取到每个对象(数据类型=对象类型 变量(遍历出来的每个对象) ...