You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

前端调用Spring Boot后端验证OTP时遇CORS拦截问题求助

解决Spring Boot + 前端的CORS跨域及OTP验证请求问题

问题背景

我是编程新手,和同伴合作开发项目,前端采用HTML/CSS/JS,后端基于Java Spring Boot。在实现OTP验证功能时遇到CORS策略拦截错误,控制台提示响应缺少Access-Control-Allow-Origin头。

后端代码

@RestController
@RequestMapping("/api/users")
@CrossOrigin(origins = "*",maxAge = 3600)
public class UserController {
    
    @Autowired
    private UserService userService;

    @PatchMapping("/verify")
    @Operation(summary = "Customer enters OTP code", description = "Check if OTP information is correct, if correct, enable it so the customer can log in")
    public ResponseEntity<?> authtotp(@RequestParam(name = "otp") String otp) {
        userService.verifyAccount(otp);
        return ResponseEntity.ok().build();
    }

    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration config = new CorsConfiguration().applyPermitDefaultValues();

        UrlBasedCorsConfigurationSource cors = new UrlBasedCorsConfigurationSource();
       
        cors.registerCorsConfiguration("/**", config);

        return cors;
    }
}

前端代码

function verifyOtp() {
    const otp1 = document.getElementById("opt1").value;
    const otp2 = document.getElementById("opt2").value;
    const otp3 = document.getElementById("opt3").value;
    const otp4 = document.getElementById("opt4").value;
    const otp5 = document.getElementById("opt5").value;
    const otp = otp1 + otp2 + otp3 + otp4 + otp5;
    
    axios.patch("http://localhost:8080/api/users/verify", { otp: otp })
        .then(response => {
            document.getElementById("verification-message").innerText = "Account verified successfully";
            document.getElementById("verification-message").style.color = "green";
            setTimeout(() => {
                window.location.href = "login.html";
            }, 3000);
        })
        .catch(error => {
            console.error("Error verifying OTP:", error.response.data.error);
            document.getElementById("verification-message").innerText = "Wrong OTP CODE!!";
            document.getElementById("verification-message").style.color = "red";
        });
}

document.addEventListener("DOMContentLoaded", function() {
    document.querySelector("button").addEventListener("click", function(event) {
        event.preventDefault();
        verifyOtp();
    });
});

控制台报错信息

Access to XMLHttpRequest at 'http://localhost:8080/api/users/verify' from origin 'http://127.0.0.1:5500' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
xhr.js:258 
        
       
       PATCH http://localhost:8080/api/users/verify net::ERR_FAILED
(anonymous) @ xhr.js:258
xhr @ xhr.js:49
qe @ dispatchRequest.js:51
value @ Axios.js:170
(anonymous) @ Axios.js:40
f @ axios.min.js:1
(anonymous) @ axios.min.js:1
(anonymous) @ axios.min.js:1
o @ axios.min.js:1
s @ Axios.js:38
(anonymous) @ Axios.js:38
n @ Axios.js:38
s.value @ Axios.js:60
(anonymous) @ Axios.js:209
(anonymous) @ bind.js:5
verifyOtp @ verifyaccount.js:37
(anonymous) @ verifyaccount.js:55
verifyaccount.js:46 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'data')
    at verifyaccount.js:46:66

问题分析与解决方法

1. CORS配置冲突问题

当前代码同时使用了@CrossOrigin注解和自定义的corsConfigurationSource方法,但自定义方法未被Spring容器识别,且两种配置可能产生冲突,导致预请求(OPTIONS)未被正确处理。

解决方式:

  • 全局CORS配置(推荐):
    创建独立的配置类,注册全局CORS规则,移除控制器上的@CrossOrigin注解避免冲突:

    @Configuration
    public class WebConfig {
        @Bean
        public CorsConfigurationSource corsConfigurationSource() {
            CorsConfiguration config = new CorsConfiguration();
            // 生产环境建议替换为具体前端域名,例如"http://127.0.0.1:5500"
            config.setAllowedOriginPatterns(Collections.singletonList("*"));
            // 明确允许PATCH和OPTIONS方法(预请求需要OPTIONS)
            config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"));
            config.setAllowedHeaders(Collections.singletonList("*"));
            config.setAllowCredentials(true);
            config.setMaxAge(3600L);
    
            UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
            source.registerCorsConfiguration("/**", config);
            return source;
        }
    }
    
  • 仅使用控制器注解:
    保留@CrossOrigin,但补充允许OPTIONS方法和所有请求头:

    @CrossOrigin(origins = "*", allowedHeaders = "*", methods = {RequestMethod.PATCH, RequestMethod.OPTIONS}, maxAge = 3600)
    

2. 请求参数不匹配问题

后端用@RequestParam接收URL参数,但前端通过请求体(JSON)发送otp,导致后端无法获取参数,同时可能干扰CORS处理流程。

解决方式:

  • 后端适配请求体:
    创建DTO类接收JSON参数:

    public class OtpRequest {
        private String otp;
    
        public String getOtp() { return otp; }
        public void setOtp(String otp) { this.otp = otp; }
    }
    

    修改接口方法:

    @PatchMapping("/verify")
    public ResponseEntity<?> authtotp(@RequestBody OtpRequest otpRequest) {
        userService.verifyAccount(otpRequest.getOtp());
        return ResponseEntity.ok().build();
    }
    
  • 前端适配URL参数:
    修改axios请求,将otp放在URL参数中:

    axios.patch(`http://localhost:8080/api/users/verify?otp=${otp}`)
    

3. 前端错误处理优化

CORS失败时error.response为undefined,直接读取error.response.data会触发类型错误,需增加判断:

.catch(error => {
    let errorMsg = "Wrong OTP CODE!!";
    if (!error.response) {
        errorMsg = "Verification request failed, please try again later";
        console.error("Request failed:", error.message);
    } else {
        console.error("Error verifying OTP:", error.response.data?.error || "Unknown error");
    }
    const msgElement = document.getElementById("verification-message");
    msgElement.innerText = errorMsg;
    msgElement.style.color = "red";
});

内容的提问来源于stack exchange,提问作者C3ddyyy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 05:55:12