前端在浏览器总报错,且获取请求头中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) {
    //     // ...
    // }
}
相关推荐
程序员黑豆5 小时前
Java包装类:基本类型与对象的桥梁
java·前端·ai编程
bugcome_com7 小时前
JWT 知识小课堂:从入门到精通,一文吃透 JSON Web Token
前端·json
To_OC8 小时前
写了三天 Next.js,我的 React 世界观被拆了又装回去
前端·全栈·next.js
独泪了无痕8 小时前
viewer.js 安装与配置指南:实现图片预览功能
前端·vue.js
mldong8 小时前
"applicant" 契约:退回发起人的闭环设计
java·架构
月华路9 小时前
G1 垃圾回收:脏卡队列、记忆集与并发精化线程机制
java·开发语言
gugucoding9 小时前
47. 【Java】Java内存模型(JMM)与可见性
java·开发语言
zww894911110 小时前
校园跑腿系统开发实战指南:从需求分析到上线部署全流程解析
java
Fluxart.ai10 小时前
电商商品图审核怎么自动化?规则引擎、人工复核与发布门禁
java·前端·自动化