集成Spring Security后Fetch POST请求报404问题求助
问题:引入Spring Security后POST请求返回404错误
我正在开发一个小型项目,引入Spring Security后,原本正常的Fetch POST请求现在一直返回POST http://localhost:8080/movie/rate 404 (Not Found)错误。我是Spring Security新手,不知道怎么解决。
前端Fetch请求代码
<script> document.getElementById('ratingSubmit').addEventListener('click', () => { let stars = document.querySelectorAll('input[name="star-rating"]'); let selectedValue = null; for (let i = 0; i < stars.length; i++) { if (stars[i].checked) { selectedValue = stars[i].value; break; } } if (selectedValue !== null) { const url = window.location.search; const urlParams = new URLSearchParams(url); if (urlParams.has('id')) { const id = urlParams.get('id'); console.log(selectedValue); console.log(id); fetch("/movie/rate", { method: 'POST', headers: { 'Content-type' : 'application/json' }, body: JSON.stringify({movie_id : id, rating : selectedValue}) }).then((resp) => { return resp.text(); }).then((resp) => { let message = 'Failed to submit'; if (resp === 'Success') message = `Successfully submitted a rating of ${selectedValue} stars`; alert(message) }) } } else { alert("No stars were selected"); } }); </script>
评分控制器代码
package javaproj.movieRental.controllers; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.security.core.Authentication; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import javaproj.movieRental.DTO.RatingRequest; import javaproj.movieRental.entities.Rating; import javaproj.movieRental.entities.User; import javaproj.movieRental.repositories.MovieRepository; import javaproj.movieRental.repositories.RatingRepository; import javaproj.movieRental.repositories.UserRepository; import javaproj.movieRental.security.CustomUserDetails; import javaproj.movieRental.services.RatingServicesImp; @Controller @RequestMapping("/movie/rate") public class RatingController { @Autowired private UserRepository userRepository; @Autowired private RatingRepository ratingRepository; @Autowired private MovieRepository movieRepository; @PostMapping(consumes = "application/json", produces = "application/json") public ResponseEntity<?> saveRating(@RequestBody RatingRequest rr, Authentication authentication) { CustomUserDetails userDetails = (CustomUserDetails) authentication.getPrincipal(); User user = userDetails.getUser(); Long user_id = user.getId(); Long movie_id = rr.getMovie_id(); int rating = rr.getRating(); System.out.println("User id: " + user_id + "\nMovie id: " + movie_id + "\nRating: " + rating ); Rating userRating = ratingRepository.getByUserIdAndMovieId(user_id, movie_id); if (userRating != null) { userRating.setRating(rating); ratingRepository.save(userRating); return ResponseEntity.ok("Success"); } RatingServicesImp rsi = new RatingServicesImp(ratingRepository, userRepository, movieRepository); userRating = rsi.createRating(user_id, movie_id, rating); ratingRepository.save(userRating); return ResponseEntity.ok("Success"); } }
SecurityConfiguration配置代码
@Bean public SecurityFilterChain securityFilterChain2(HttpSecurity http) throws Exception { http .authorizeHttpRequests(authorize -> authorize .requestMatchers(HttpMethod.POST, "/movie/rate") .hasAnyRole("ADMIN", "USER") .anyRequest().authenticated() // All other requests require authentication ) .formLogin(formLogin -> formLogin .loginPage("/login") // Custom login page URL .successHandler(customAuthenticationSuccessHandler) // Use custom success handler .permitAll() ) .logout(logout -> logout .invalidateHttpSession(true) .clearAuthentication(true) .logoutRequestMatcher(new AntPathRequestMatcher("/logout")) .logoutSuccessUrl("/login?logout") .permitAll() ) .exceptionHandling(exception -> exception .accessDeniedPage("/error/403") // Custom 403 error page ); return http.build(); }
解决方向
1. 修正控制器注解
控制器使用@Controller注解,但方法返回ResponseEntity,这会导致Spring试图解析视图名称而非直接返回响应体,引发404。将注解替换为@RestController,或在方法上添加@ResponseBody:
@RestController // 替换原@Controller @RequestMapping("/movie/rate") public class RatingController { // 原有代码不变 }
2. 处理CSRF防护
Spring Security默认开启CSRF防护,POST请求需携带CSRF令牌,否则会被拦截(可能表现为404/403)。
- 在页面添加CSRF元标签:
<meta name="_csrf" content="${_csrf.token}"/> <meta name="_csrf_header" content="${_csrf.headerName}"/>
- 在Fetch请求中添加CSRF头:
const csrfToken = document.querySelector('meta[name="_csrf"]').content; const csrfHeader = document.querySelector('meta[name="_csrf_header"]').content; fetch("/movie/rate", { method: 'POST', headers: { 'Content-type' : 'application/json', [csrfHeader]: csrfToken }, body: JSON.stringify({movie_id : id, rating : selectedValue}) })
3. 检查Security配置优先级
如果存在多个SecurityFilterChain Bean,需确保当前配置优先生效,可添加@Order注解:
@Bean @Order(1) public SecurityFilterChain securityFilterChain2(HttpSecurity http) throws Exception { // 原有配置不变 }
4. 验证RatingRequest属性匹配
确保RatingRequest类的movie_id、rating字段与前端JSON字段完全一致,且包含对应的getter/setter方法,否则Spring无法解析请求体。
内容的提问来源于stack exchange,提问作者LearningCode
相关产品推荐
相关产品推荐

