前端在浏览器总报错,且获取请求头中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) {
    //     // ...
    // }
}
相关推荐
冰暮流星13 小时前
javascript的switch语句介绍
java·前端·javascript
有梦想的攻城狮13 小时前
Java中的Double类型的存在精度丢失详解
java·开发语言·bigdecimal·double
m0_7482495413 小时前
Java 语言提供了八种基本类型【文123】
java·开发语言·python
移幻漂流14 小时前
Kotlin 如何解决 Java 的核心痛点:现代语言特性的深度剖析
java·python·kotlin
leikooo14 小时前
ShardingSphere 下更新分片键导致的失败问题分析与解决
java·spring·apache
a程序小傲14 小时前
中国邮政Java面试被问:Netty的FastThreadLocal优化原理
java·服务器·开发语言·面试·职场和发展·github·哈希算法
做科研的周师兄14 小时前
【MATLAB 实战】|多波段栅格数据提取部分波段均值——批量处理(NoData 修正 + 地理信息保真)_后附完整代码
前端·算法·机器学习·matlab·均值算法·分类·数据挖掘
jay神14 小时前
基于Java的水果网上订购平台
java·mysql·vue·springboot·计算机毕业设计
da_vinci_x14 小时前
图标量产:从“手绘地狱”到“风格克隆”?Style Reference 的工业化实战
前端·游戏·ui·prompt·aigc·设计师·游戏美术
小北方城市网14 小时前
SpringBoot 集成 MyBatis-Plus 实战(高效 CRUD 与复杂查询):简化数据库操作
java·数据库·人工智能·spring boot·后端·安全·mybatis