Angular 和 Spring 启动 - POST 请求成为 OPTIONS

Posted

技术标签:

【中文标题】Angular 和 Spring 启动 - POST 请求成为 OPTIONS【英文标题】:Angular and Spring boot - POST Request become OPTIONS 【发布时间】:2020-04-18 05:31:34 【问题描述】:

我正在使用 Spring boot(和 Spring Security)和 Angular 开发我的 API。

你的 TypeScript 代码:

return this.http.post<any>('http://localhost:8080/users',
        
            firstName: 'Clemi',
            lastName: 'Le boss',
            mail: 'clemclem'
        );

我的控制器:

@RestController
@RequestMapping(path = "/users")
public class UserController

    @Autowired
    private UserService userService;
...
    @PostMapping()
    public ResponseEntity<Object> addUser(Principal principal, @RequestBody User user) 
        User savedUser = userService.save(user);

        return new ResponseEntity<Object>(HttpStatus.OK);
    


以及安全配置:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter 
    @Autowired
    UserService userDetailsService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception 
        auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
    
    @Override
    protected void configure(HttpSecurity http) throws Exception 
        http.csrf()
                .disable()
                .exceptionHandling()
                .authenticationEntryPoint(new Http403ForbiddenEntryPoint() 
                )
                .and()
                    .authenticationProvider(getProvider())
                    .formLogin()
                    .loginProcessingUrl("/login")
                    .successHandler(new AuthentificationLoginSuccessHandler())
                    .failureHandler(new SimpleUrlAuthenticationFailureHandler())
                .and()
                    .logout()
                    .logoutUrl("/logout")
                    .logoutSuccessHandler(new AuthentificationLogoutSuccessHandler())
                    .invalidateHttpSession(true)
                .and()
                    .authorizeRequests()
                    .antMatchers("/login").permitAll()
                    .antMatchers("/logout").permitAll()
                    .antMatchers(HttpMethod.GET, "/users/**").authenticated()
                    .antMatchers(HttpMethod.DELETE, "/users/**").hasRole("ADMIN")
                    .antMatchers(HttpMethod.PUT).hasRole("USER")
                    .anyRequest().permitAll()
                .and()
                    .httpBasic();
    

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() 
        return new BCryptPasswordEncoder();
    

    private class AuthentificationLoginSuccessHandler extends SimpleUrlAuthenticationSuccessHandler 
        @Override
        public void onAuthenticationSuccess(HttpServletRequest request,
                                            HttpServletResponse response, Authentication authentication)
                throws IOException, ServletException 
            response.setStatus(HttpServletResponse.SC_OK);
        
    

    private class AuthentificationLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler 
        @Override
        public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response,
                                    Authentication authentication) throws IOException, ServletException 

            response.setStatus(HttpServletResponse.SC_OK);
        
    

    @Bean
    public AuthenticationProvider getProvider() 
        AuthService provider = new AuthService();
        provider.setUserDetailsService(userDetailsService);
        provider.setPasswordEncoder(bCryptPasswordEncoder());
        return provider;
    

当我使用邮递员时,我的请求工作正常。但是当我使用我的前端时,每个请求都变成了 OPTIONS 请求。我阅读了多篇文章,解释这是因为 Cross Origin Request 并且可能是“预检请求”,但我不知道如何解决它......

有什么想法吗?

【问题讨论】:

在生产中,您是否计划从同一个 URL 为 Angular 应用程序和 REST 服务提供服务?如果是这样,让 ng 充当 Spring 的反向代理:github.com/angular/angular-cli/blob/master/docs/documentation/…,并从您的 URL 中删除“localhost:8080”(这对您自己的开发机器没有任何意义)。 您需要将HttpMethod.OPTIONS列入白名单 【参考方案1】:

该行为是由于 CORS 造成的。它们是处理这种行为的两种方法。

    ACCEPT HEADER 在服务器端。这确实可行,但在服务器代码中添加 accept 标头不是一个好习惯。 PROXY 对于任何具有servicefrontend 的应用程序来说,一个非常常见的架构是它们之间有代理管理器,例如nginxapache。但这同样适用于production env。出于开发目的,angular cli 与内置的lite-server 捆绑在一起,它在ng serve 上托管实时预览。这是在lite server 上设置代理所需的配置。

我。在 Angular 项目的根目录下创建一个文件调用 proxy-config.json。 ii.根据服务器地址添加关注内容。


  "/api": 
    "target": "http://localhost:8080/",
    "changeOrigin": true,
    "secure": false,
    "pathRewrite": 
       '^/api': ''
     
   

/api 是您的 Angular 应用程序中所有端点的 proxy 部分

http://localhost:8080/accounts(actual server endpoint) -----> http://localhost:8080/api/accounts(proxy end point)

然后在package.json中修改如下脚本命令

"start": "ng serve --proxy-config proxy.config.json --port 4200",

【讨论】:

【参考方案2】:

问题是由 CORS 引起的。您需要接受来自另一个域的请求(仅用于本地开发),如图所示here

【讨论】:

以上是关于Angular 和 Spring 启动 - POST 请求成为 OPTIONS的主要内容,如果未能解决你的问题,请参考以下文章

如何使基本身份验证作为 Angular JS/Spring 启动应用程序中 keycloak 的替代品

spring bootRun 和 Angular buildWatch 使用 Gradle

减少 Spring Boot 可执行 jar Angular App 的磁盘空间

删除表中的每条记录时重新启动Id = 1? (角度 + Spring Boot + MySQL)

Angular 的 Spring Boot 授权服务器访问 - 不断给出 CORS 错误

将 Spring Boot - Angular 应用程序部署到 digitalocean