前端在浏览器总报错,且获取请求头中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) {
    //     // ...
    // }
}
相关推荐
傻小胖21 分钟前
vue3中Teleport的用法以及使用场景
前端·javascript·vue.js
wl85111 小时前
Vue 入门到实战 七
前端·javascript·vue.js
2501_903238651 小时前
自定义登录页面的Spring Security实践
java·后端·spring·个人开发
Enti7c1 小时前
用 HTML、CSS 和 JavaScript 实现抽奖转盘效果
前端·css
LCG元1 小时前
Vue.js组件开发-使用Vue3如何实现上传word作为打印模版
前端·vue.js·word
飞翔的佩奇2 小时前
Java项目: 基于SpringBoot+mybatis+maven+mysql实现的图书管理系统(含源码+数据库+答辩PPT+毕业论文)
java·数据库·spring boot·mysql·spring·毕业设计·图书管理
dal118网工任子仪2 小时前
94,【2】buuctf web [安洵杯 2019]easy_serialize_php
android·前端·php
大模型铲屎官2 小时前
HTML5 技术深度解读:本地存储与地理定位的最佳实践
前端·html·html5·本地存储·localstorage·地理定位·geolocation api
一 乐3 小时前
基于vue船运物流管理系统设计与实现(源码+数据库+文档)
前端·javascript·数据库·vue.js·spring boot·后端·船运系统
m0_528723813 小时前
在React中使用redux
前端·javascript·react.js