栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

前端请求进入后端,异常捕获返回结果后前端却显示跨域

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

前端请求进入后端,异常捕获返回结果后前端却显示跨域

1、前言

  后端是 Springboot 项目,通过自定义拦截器进行 token 校验,校验不通过则抛出异常让全局捕获异常返回。自认为逻辑相当合理,且 postman 都已测试过没问题。
  然后问题来了,前端通过 ajax 请求,request 到了后端校验进行 token 校验,抛出了自定义 Token 校验异常后被捕获返回了结果,该请求肆虐了后端这些步骤后返回,但是前端却显示跨域。

Access to XMLHttpRequest at ‘http://192.168.129.155:9999/affairs/api/commons/locker/check’ from origin ‘http://jsrun.net’ has been blocked by CORS policy: No ‘Access-Control-Allow-Origin’ header is present on the requested resource.

  而后端已经进行了跨域的处理,通过 @CrossOrigin(allowCredentials = “true”) 添加到 baseController 上。

注: postman 或浏览器直接访问目标地址不是跨域问题。跨域问题是存在两个站点间的调用。

2、代码 2.1 token 拦截器
@Slf4j
public class TokenInterceptor implements HandlerInterceptor {

    @Autowired
    YunBasicApiService yunBasicApiService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object) throws Exception {
        // 从 http 请求头中取出 token
        String token = request.getHeader("token");
        // 如果不是映射到方法直接通过
        if (!(object instanceof HandlerMethod)) {
            return true;
        }
        HandlerMethod handlerMethod = (HandlerMethod) object;
        Method method = handlerMethod.getMethod();
        // 检查用户权限的注解(带有 @CheckToken 注解的地址都会进行 token 校验)
        if (method.isAnnotationPresent(CheckToken.class)) {
            CheckToken checkToken = method.getAnnotation(CheckToken.class);
            if (checkToken.required()) {
                return checkToken(request, response, token);
            }
        }
        return true;
    }

    
    private boolean checkToken(HttpServletRequest request, String token) throws Exception {
        // 执行认证
        if (StringUtils.isBlank(token)) {
            log.error(request.getContextPath() + ":token为空");
            throw new TokenException();
        }
        // 基础平台获取用户信息
        UserInfo userInfo = yunBasicApiService.getUserInfo(token);
        if(userInfo == null || StringUtils.isBlank(userInfo.getUserId())) {
            log.error(request.getContextPath() + ":token认证失败:" + token);
            throw new TokenException();
        }
        request.setAttribute("userInfo", userInfo);
        return true;
    }
}
2.2 自定义 token 校验注解
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface CheckToken {
    boolean required() default true;
}
2.3 拦截器配置

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {

    
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // token 拦截所有请求,通过判断是否有 @CheckToken 注解 决定是否需要校验
        registry.addInterceptor(tokenInterceptor()).addPathPatterns("
    @Bean
    public TokenInterceptor tokenInterceptor() {
        return new TokenInterceptor();
    }
}
2.4 自定义 Token 校验异常
public class TokenException extends Exception {

    private static final long serialVersionUID = 845941496134964616L;

    public TokenException() {
        super("Token 无法认证");
    }
}
2.5 全局捕获异常
@ControllerAdvice
public class GlobalExceptionHandler {

    
    @ExceptionHandler(TokenException.class)
    public ResponseEntity> tokenException(TokenException e) {
        e.printStackTrace();
        Map map = setResultMap(401, "token 认证失败");
        return new ResponseEntity<>(map, HttpStatus.UNAUTHORIZED);
    }

    
    @ExceptionHandler(Exception.class)
    public ResponseEntity> globalException(Exception e) {
        Map map = setResultMap(500, "服务器异常,请联系管理员:" + e.getMessage());
        e.printStackTrace();
        return new ResponseEntity<>(map, HttpStatus.INTERNAL_SERVER_ERROR);
    }

    
    private Map setResultMap(Integer code, Object msg) {
        Map map = new HashMap<>(16);
        map.put("code", code);
        map.put("msg", msg);
        return map;
    }
}
2.6 Controller
@RestController
@RequestMapping(value = "commons/locker")
public class LockerController extends AbstractbaseController {

    @Autowired
    YunBasicApiService yunBasicApiService;

    
    @GetMapping(value = "check")
    @CheckToken
    public baseResult checkLock() throws Exception {
        return success(yunBasicApiService.checkLocker());
    }
}
3、尝试并解决 3.1 查询资料

  网上查看资料,后端处理很多都说是设置响应头如下:

response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));

  还有在上述代码中的 InterceptorConfig 里重写 WebMvcConfigurer 接口里的 addCorsMappings 方法,如下

@Override
public void addCorsMappings(CorsRegistry registry) {
	registry.addMapping("
    private boolean checkToken(HttpServletRequest request, HttpServletResponse response, String token) throws Exception {
        // ----  避免前端出现无法获取返回结果的情况,以下校验不通过不进行抛出异常,直接设置返回 ---- //
        // 执行认证
        if (StringUtils.isBlank(token)) {
            log.error(request.getContextPath() + ":token为空");
            setResultJson(response, "token 不可为空");
            return false;
        }
        // 基础平台获取用户信息
        UserInfo userInfo = yunBasicApiService.getUserInfo(token);
        if(userInfo == null || StringUtils.isBlank(userInfo.getUserId())) {
            log.error(request.getContextPath() + ":token认证失败:" + token);
            setResultJson(response, "token 认证失败");
            return false;
        }
        request.setAttribute("userInfo", userInfo);
        return true;
    }

    
    private void setResultJson(HttpServletResponse response, String msg) throws Exception {
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json;charset=utf-8");
        response.setStatus(HttpStatus.UNAUTHORIZED.value());
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        PrintWriter writer = response.getWriter();
        JSONObject resultJson = new JSONObject();
        resultJson.put("code", 401);
        resultJson.put("msg", msg);
        writer.append(resultJson.toJSONString());

  这样就成功了。

4、待解决

  至于原来的方式无法解决跨域,并不是无法解决。无需经过 token 拦截器的 API 就可以解决,经过 token 拦截器且校验失败的则不行

  我猜想是因为拦截器中抛出异常,全局捕获后返回的结果在两个域间出现了问题。但具体为啥会这样,还有待研究。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/340130.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号