前端在浏览器总报错,且获取请求头中token的值为null

前端请求总是失败说受跨域请求影响,但前后端配置已经没有问题了,如下:

java 复制代码
package com.example.shop_manage_sys.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import com.example.shop_manage_sys.Interceptor.TokenInterceptor;

@Configuration
public class CorsConfig implements WebMvcConfigurer {

    @Autowired
    private TokenInterceptor jwtInterceptor;
//cors配置
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")  // Applies CORS to all paths
                .allowedOrigins("http://127.0.0.1:8081", "http://localhost:8081")  // List specific allowed origins
                .allowedMethods("GET", "POST", "PUT", "DELETE","OPTIONS")
                .allowedHeaders("accept", "content-type", "origin", "custom-header","token")
                .allowCredentials(true)
                .maxAge(3600); 
    }
//拦截器配置
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(jwtInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns("/sms/*"); // 排除不需要拦截的路径
    }
}

后端获取前端请求头中自定义的token字段时获取到null,这是因为浏览器端会在请求前总发出一次预检请求,后端的拦截器将这种options请求直接放行即可。

示例拦截器代码:

java 复制代码
package com.example.shop_manage_sys.Interceptor;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
// import org.springframework.web.servlet.ModelAndView;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import org.springframework.http.MediaType;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.server.ServletServerHttpResponse;


// import java.util.Base64;

@Component
public class TokenInterceptor implements HandlerInterceptor {
    @Value("${jwt.secret}")
    private String SECRET_KEY;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
            // 直接放行预检请求
            return true;
        }
        
        String token = request.getHeader("token");
        if (token != null && !token.isEmpty()) {
            try {
                // 验证并解析token
                Key key = Keys.hmacShaKeyFor(SECRET_KEY.getBytes(StandardCharsets.UTF_8));
                Jws<Claims> claimsJws = Jwts.parserBuilder()
                                            .setSigningKey(key)
                                            .build()
                                            .parseClaimsJws(token);
                Claims claims = claimsJws.getBody();
                request.setAttribute("claims", claims);
                return true;
            } catch (Exception e) {
                handleJwtError(response, "Invalid or expired token.");
                return false;
            }
        } else {
            handleJwtError(response, "Token is missing.");
            return false;
        }
    }

    private void handleJwtError(HttpServletResponse response, String errorMessage) {
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        response.setCharacterEncoding(StandardCharsets.UTF_8.name());
    
        try {
            // Wrap the ServletOutputStream in a ServletServerHttpResponse
            ServletServerHttpResponse outputMessage = new ServletServerHttpResponse(response);
            // Convert the JSON string to an Object
            Object jsonContent = "{\"error\": \"" + errorMessage + "\"}";
            
            // Write the JSON content to the output stream
            new MappingJackson2HttpMessageConverter().write(jsonContent, MediaType.APPLICATION_JSON, outputMessage);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    // 你可以选择性实现以下方法,但在这个场景下它们可能不是必须的
    // @Override
    // public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
    //     // ...
    // }
    //
    // @Override
    // public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
    //     // ...
    // }
}
相关推荐
千寻girling5 分钟前
马上元旦节了,手写一个《前端脚手架》庆祝一下 !
前端
qq_124987075317 分钟前
基于微信小程序的电子元器件商城(源码+论文+部署+安装)
java·spring boot·spring·微信小程序·小程序·毕业设计
嚣张丶小麦兜22 分钟前
认识vite
前端·javascript·vue.js
吃喝不愁霸王餐APP开发者23 分钟前
基于Spring Cloud Gateway实现对外卖API请求的统一鉴权与流量染色
java·开发语言
a努力。26 分钟前
美团Java面试被问:Redis集群模式的工作原理
java·redis·后端·面试
一雨方知深秋35 分钟前
面向对象编程
java·封装·this·构造器·static关键字·成员变量·javabean实体类
资生算法程序员_畅想家_剑魔38 分钟前
Java常见技术分享-11-责任链模式
java·spring boot·责任链模式
玲小珑1 小时前
请求 ID 跟踪模式:解决异步请求竞态条件
前端
计算机程序设计小李同学1 小时前
动漫之家系统设计与实现
java·spring boot·后端·web安全
开心_开心急了1 小时前
AI+PySide6实现自定义窗口标题栏目(titleBar)
前端