执行 POST 请求时的 Spring Boot 端点 403 OPTIONS

Posted

技术标签:

【中文标题】执行 POST 请求时的 Spring Boot 端点 403 OPTIONS【英文标题】:Springboot endpoint 403 OPTIONS when doing a POST request 【发布时间】:2018-09-03 09:36:25 【问题描述】:

我正在使用 Spring 运行服务,并且我的 Angular 前端在尝试发出 POST 请求时收到带有 Request Method: OPTIONS 的 403。

Spring 服务和 Angular 应用程序都在我的机器上本地运行。我尝试使用 Chrome 插件切换 CORS,但这似乎无法解决问题。

我对服务的所有 GET 请求似乎都可以正常工作。我可以在 Postman 中发出 POST 请求,所以我不确定为什么 Angular 应用程序无法发出请求,但 Postman 可以。

****编辑****

响应标头

Allow: GET, HEAD, POST, PUT, DELETE, OPTIONS, PATCH
Content-Length: 20
Date: Sat, 31 Mar 2018 19:15:01 GMT

请求标头

Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Access-Control-Request-Headers: content-type
Access-Control-Request-Method: POST
Connection: keep-alive
Host: localhost:9901
Origin: http://localhost:4200
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_3) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/65.0.3325.162 Safari/537.36

【问题讨论】:

发布请求与发布数据一起使用。 @RomanC 是的,我的 Angular 应用程序正在使用 httpClient 使用 json 对象进行 post 调用。 但是不行 【参考方案1】:

如果我们谈论的是 SpringBoot,可能是最新版本或至少是最新版本,那么我们可以简单地在控制器类中使用 @CrossOrigin 注释旁边的 @RestController 注释。它从 Spring 版本开始可用。 4.2

例如:

@RestController
@CrossOrigin
@RequestMapping("/api")
public class MyObjectsController 
    private final MyObjectsService service;

    @Autowired
    public MyObjectsController(MyObjectsService service) 
        this.service = service;
    

    @GetMapping("/version")
    public Version getVersion() 
        return service.getVersion();
    

    @PostMapping("/objects")
    public ObjectResource createObject(@RequestBody @Valid ObjectData data) 
        return service.createObject(data);
    

    @GetMapping("/objects/id")
    public ObjectResource getObject(@PathVariable String id) 
        return service.getObjectById(id);
    


好处:

带注释的控制器比任何类型的自写过滤器表现得更好(也更智能) 它也比整个项目的固定 CORS 配置更灵活,因为您可以控制 API 的哪些部分应支持 CORS 标头以及哪些部分应仅可用于服务器到服务器的通信 只有控制器支持的方法才会在 OPTIONS 请求的响应中被声明和允许 CORS 标头只会出现在对 CORS 请求的响应中(即分析 Referer 标头的存在) 等

另见:

Enabling Cross Origin Requests for a RESTful Web Service CrossOrigin Annotation javadoc

【讨论】:

【参考方案2】:

要修复 Angular(前端)和 Spring Boot(后端)项目中的所有 CORS 问题,请添加以下 Spring 组件:

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.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class ConfigCtrl implements Filter 
    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException 
        final HttpServletResponse response = (HttpServletResponse) res;
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type");
        response.setHeader("Access-Control-Max-Age", "3600");
        if ("OPTIONS".equalsIgnoreCase(((HttpServletRequest) req).getMethod())) 
            response.setStatus(HttpServletResponse.SC_OK);
         else 
            chain.doFilter(req, res);
        
    
    @Override
        public void destroy() 
    
    @Override
        public void init(FilterConfig config) throws ServletException 
    

对于初学者的 PS:类的名称及其在 Spring 应用程序中的位置无关紧要。 Credit to Ajitesh Kumar.

【讨论】:

尝试使用 WebMvcConfigurer 执行此操作但未成功。过滤器有效【参考方案3】:

CORS 请求由您的前端发出,以查看您支持的方法 (HTTP Verbs) 是什么。这通常是货币操作所必需的,例如用于修改数据的 POSTPUT

因此您的前端将首先进行此调用,并且您的后端需要使用允许的方法进行响应,您还可以限制特定的 URI,然后在成功验证后进行目标调用。

这是完全正常的,Angular 会在内部执行此操作,以免在不知道服务器是否允许的情况下发出不必要的数据请求。

Spring 中设置它的方法如下。

    //Change/Customize as necessary
    @Bean
    CorsConfigurationSource corsConfigurationSource() 
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("<your origin>");
        corsConfiguration.setAllowedMethods(Arrays.asList(
                HttpMethod.GET.name(),
                HttpMethod.HEAD.name(),
                HttpMethod.POST.name(),
                HttpMethod.PUT.name(),
                HttpMethod.DELETE.name()));
        corsConfiguration.setMaxAge(1800L);
        source.registerCorsConfiguration("/**", corsConfiguration); // you restrict your path here
        return source;
    

如果您还在后端使用任何自定义 response headers,那么您也需要在 CORS 配置中允许这样做。 举个例子

    corsConfiguration.addAllowedHeader("*");
    corsConfiguration.addExposedHeader("header1");
    corsConfiguration.addExposedHeader("header2");

【讨论】:

所以我将此 Bean 声明添加到我的应用程序类中,就在我的 main 下方。当我尝试执行 POST 操作时,我似乎仍然收到 403 OPTIONS Invalid CORS request 错误。我在 Angular 端有什么需要做的吗? 您在选项请求中收到的标头是什么?阅读此内容可能会对您有所帮助github.com/spring-projects/spring-security-oauth/issues/938 将失败请求的标头添加到帖子中:) 如果您想将其添加到您提交的答案代码中,我会将其标记为复选标记!:) corsConfiguration 类中有maxAgeorigins 选项,我已经在上面添加了这些设置器。

以上是关于执行 POST 请求时的 Spring Boot 端点 403 OPTIONS的主要内容,如果未能解决你的问题,请参考以下文章

在 Spring boot 中使用 post 方法保存多个实体时的无限循环

Spring Boot POST 请求返回 Null 值的端点

spring boot应用集成cas单点登录,post请求拿不到参数

Spring boot - 一些 POST 请求严重延迟

缺少请求正文的 Spring Boot POST 请求?

无法将http post请求发送到spring boot