使用Spring Framework为OPTIONS请求启用CORS

每次我对我的服务进行PUT Ajax调用时,都会返回以下错误:

XMLHttpRequest无法加载http:// localhost:8080 / users / edit 。 对预检请求的响应未通过访问控制检查:请求的资源上不存在“Access-Control-Allow-Origin”标头。 因此不允许来源’ http:// localhost:63342 ‘访问。 响应具有HTTP状态代码403。

经过2天的调查,我已经到达了我的代码上尝试下一个解决方案。

这是我加载必要的类并运行应用程序的主类

@SpringBootApplication @EnableAutoConfiguration public class Application extends SpringBootServletInitializer{ public static void main(String[] args) { SpringApplication.run(Application.class, args); } @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { return application.sources(DispatcherServletInitializer.class, OptionsController.class,Application.class); } } 

DispatcherServilet初始化程序 ,我在其中启用dispatchOptionsRequest:

 public abstract class DispatcherServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { @Override protected void customizeRegistration(ServletRegistration.Dynamic registration) { registration.setInitParameter("dispatchOptionsRequest", "true"); super.customizeRegistration(registration); } } 

用于处理所有OPTIONS请求的控制器

 @Controller public class OptionsController { @RequestMapping(method = RequestMethod.OPTIONS) public HttpServletResponse handle(HttpServletResponse theHttpServletResponse) throws IOException { theHttpServletResponse.addHeader("Access-Control-Allow-Headers", "origin, content-type, accept, x-requested-with"); theHttpServletResponse.addHeader("Access-Control-Max-Age", "60"); theHttpServletResponse.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"); theHttpServletResponse.addHeader("Access-Control-Allow-Origin", "*"); return theHttpServletResponse; } } 

我配置错误了什么?

最后, DispatcheServlet自定义初始化程序是真正解决了我的问题的类。 由于我实施的optionsController ,OPTIONS请求失败了,这是错误的。

所以我删除了那个optionsController ,只是在我的Rest Controller中为OPTIONS请求添加了handle方法,问题就解决了:

 @CrossOrigin(origins = "*", maxAge = 3600) @RestController @RequestMapping("/users") public class Users { @RequestMapping( value = "/edit", method = RequestMethod.PUT) public ResponseEntity create(@RequestBody User user){ .... .... } @RequestMapping( value = "/**", method = RequestMethod.OPTIONS ) public ResponseEntity handle() { return new ResponseEntity(HttpStatus.OK); } } 

如果您使用Spring(4.2)的现代版本,您可以从@CrossOrigin中受益。 实际上,如果您使用Spring <4.2v,您可以创建一个Servlet过滤器并听取CORS支持的标题,如下所示:

 package it.valeriovaudi.web.filter; import javax.servlet.*; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.HashMap; import java.util.Map; /** Copyright 2015 Valerio Vaudi Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ public class CORSFilter implements Filter { public static final String ACCESS_CONTROL_ALLOW_ORIGIN_NAME = "Access-Control-Allow-Origin"; public static final String DEFAULT_ACCESS_CONTROL_ALLOW_ORIGIN_VALUE = "*"; public static final String ACCESS_CONTROL_ALLOW_METHDOS_NAME = "Access-Control-Allow-Methods"; public static final String DEFAULT_ACCESS_CONTROL_ALLOW_METHDOS_VALUE = "POST, GET, OPTIONS, DELETE"; public static final String ACCESS_CONTROL_MAX_AGE_NAME = "Access-Control-Max-Age"; public static final String DEFAULT_ACCESS_CONTROL_MAX_AGE_VALUE = "3600"; public static final String ACCESS_CONTROL_ALLOW_HEADERS_NAME = "Access-Control-Allow-Headers"; public static final String DEFAULT_ACCESS_CONTROL_ALLOW_HEADERS_VALUE = "x-requested-with"; private String accessControlAllowOrigin = DEFAULT_ACCESS_CONTROL_ALLOW_ORIGIN_VALUE; private String accessControlAllowMethods = DEFAULT_ACCESS_CONTROL_ALLOW_METHDOS_VALUE; private String accessControlAllowMaxAge = DEFAULT_ACCESS_CONTROL_MAX_AGE_VALUE; private String accessControlAllowHeaders = DEFAULT_ACCESS_CONTROL_ALLOW_HEADERS_VALUE; /** * @return the method return a map that associated the name of paramiters in the web.xml to the class variable name for the header binding*/ private Map initConfig(){ Map result = new HashMap<>(); result.put(ACCESS_CONTROL_ALLOW_ORIGIN_NAME,"accessControlAllowOrigin"); result.put(ACCESS_CONTROL_ALLOW_METHDOS_NAME,"accessControlAllowMethods"); result.put(ACCESS_CONTROL_MAX_AGE_NAME,"accessControlAllowMaxAge"); result.put(ACCESS_CONTROL_ALLOW_HEADERS_NAME,"accessControlAllowHeaders"); return result; } @Override public void init(FilterConfig filterConfig) throws ServletException { String initParameterValue; Map stringStringMap = initConfig(); for (Map.Entry stringStringEntry : stringStringMap.entrySet()) { initParameterValue = filterConfig.getInitParameter(stringStringEntry.getKey()); // if the init paramiter value isn't null then set the value in the correct http header if(initParameterValue!=null){ try { getClass().getDeclaredField(stringStringEntry.getValue()).set(this, initParameterValue); } catch (IllegalAccessException | NoSuchFieldException ignored) { } } } } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletResponse response = (HttpServletResponse) servletResponse; response.setHeader(ACCESS_CONTROL_ALLOW_ORIGIN_NAME, accessControlAllowOrigin); response.setHeader(ACCESS_CONTROL_ALLOW_METHDOS_NAME, accessControlAllowMethods); response.setHeader(ACCESS_CONTROL_MAX_AGE_NAME, accessControlAllowMaxAge); response.setHeader(ACCESS_CONTROL_ALLOW_HEADERS_NAME, accessControlAllowHeaders); filterChain.doFilter(servletRequest, servletResponse); } @Override public void destroy() { } } 

在Spring启动中,您可以将此filter注册为spring bean,Spring将为您注册filter。

我希望这可以帮到你。