Java 使用 Spring Framework 为 OPTIONS 请求启用 CORS
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/37733501/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Enable CORS for OPTIONS request using Spring Framework
提问by daniegarcia254
Every time I make a PUT Ajax call to my service, it return the following error:
每次我对我的服务进行 PUT Ajax 调用时,它都会返回以下错误:
XMLHttpRequest cannot load http://localhost:8080/users/edit. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:63342' is therefore not allowed access. The response had HTTP status code 403.
XMLHttpRequest 无法加载http://localhost:8080/users/edit。对预检请求的响应未通过访问控制检查:请求的资源上不存在“Access-Control-Allow-Origin”标头。因此,不允许访问Origin ' http://localhost:63342'。响应具有 HTTP 状态代码 403。
After 2 days of investigation, I've reached to try the next solution on my code.
经过 2 天的调查,我已经尝试在我的代码上尝试下一个解决方案。
This is the main classwhere I load the necessary classes and run the application:
这是我加载必要类并运行应用程序的主类:
@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);
}
}
The DispatcherServilet initializer, where I enable the dispatchOptionsRequest:
该DispatcherServilet初始化,在那里我启用dispatchOptionsRequest:
public abstract class DispatcherServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected void customizeRegistration(ServletRegistration.Dynamic registration) {
registration.setInitParameter("dispatchOptionsRequest", "true");
super.customizeRegistration(registration);
}
}
A controllerfor handle all OPTIONS request:
一个控制器,用于处理所有选项要求:
@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;
}
}
What I'm doing wrong with the configuration?
我在配置上做错了什么?
采纳答案by daniegarcia254
Finally, the DispatcheServletcustomize initializer was the class that really solved my problem. The OPTIONS request was failing because of the optionsControllerI had implemented, it was wrong.
最后,DispatcheServlet自定义初始值设定项是真正解决我的问题的类。OPTIONS 请求由于我实施的optionsController而失败,这是错误的。
So I removed that optionsController, and just by adding the handlemethod in my Rest Controller for the OPTIONS request, the problem was solved:
所以我删除了那个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);
}
}
回答by Valerio Vaudi
If you use a modern version of Spring (4.2) you can benefit of the @CrossOrigin. Indeed if you use Spring < 4.2v you can create a Servlet Filter and put hear the header for CORS support like below:
如果您使用现代版本的 Spring (4.2),您可以受益于 @CrossOrigin。实际上,如果您使用 Spring < 4.2v,您可以创建一个 Servlet 过滤器,并将用于 CORS 支持的 header 放入如下所示:
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<String,String> initConfig(){
Map<String, String> 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<String, String> stringStringMap = initConfig();
for (Map.Entry<String, String> 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() {
}
}
in Spring boot you can register this filter as spring bean and Spring will register the filter for you.
在 Spring boot 中,您可以将此过滤器注册为 spring bean,Spring 将为您注册过滤器。
I hope that this can help you.
我希望这可以帮助你。