Controller中的@PostMapping和@PutMapping无法区分

我自定义了一个过滤器,用于对验证码进行校验,大概如下:

public class CaptchaFilter extends OncePerRequestFilter {
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) {
....
    }
}

在过滤方法中,我过滤了特定的POST和PUT方法,也写了filterChain.doFilter(request, response);,但是到了controller,同一个url对应的@PostMapping和@PutMapping却无法区分了,总是报405错误。

求助各位,帮忙看看可能是哪里有问题?

你是想通过拦截器统一校验验证码吗?405是请求方式不支持,你的信息太少了,不怎么好确定问题。

我是想实现一个统一的验证码校验,但是,现在情况看起来就是:一个请求经过了上面的过滤器后,到了Controller就不能使用RESTful风格的请求了,无法区分请求方法了,比如同一个url同时存在@PostMapping和@PutMapping,就会报405错误。
过滤器的实现如下:

    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
        throws ServletException, IOException {
        //  确定请求路径是否需要验证验证码
        boolean condition = false;
        for (String path : captchaFilterPathList) {
            condition = MATCHER.match(path, request.getServletPath());
            if (condition) break;
        }
        // 只拦截POST和PUT方法
        if (condition && (HttpMethod.POST.name().equals(request.getMethod())) ||
            HttpMethod.PUT.name().equals(request.getMethod())) {
            // 做验证
            try {
                doCaptchaValidation(request);
                // 验证无误后进入下一个过滤器,否则应该在此终止
                filterChain.doFilter(request, response);
            } catch (CaptchaException exception) {
                request.getRequestDispatcher(captchaFailureHandlePath + "?message=" + URLEncoder.encode(exception.getMessage(), "UTF-8")).forward(request, response);
            }
        } else {
            filterChain.doFilter(request, response);
        }
    }

    private void doCaptchaValidation(HttpServletRequest request) throws CaptchaException {
        logger.debug("正在做验证码验证。。。");
        String captcha = request.getParameter(requestParameterKey);
        request.removeAttribute(requestParameterKey);
        Object credentials = request.getSession().getAttribute(sessionAttributeKey);
        if (captcha == null) {
            throw new CaptchaException("验证码不能为空");
        } else if (credentials == null) {
            throw new CaptchaException("会话已经过期,请刷新验证码");
        } else {
            CharImageCaptcha imageCaptcha = (CharImageCaptcha) credentials;
            if (imageCaptcha.isExpired()) {
                throw new CaptchaException("验证码已经过期,请刷新验证码");
            } else if (captcha.toUpperCase().equals(imageCaptcha.getCode())) {
                // 验证成功,删除session中的验证码
                request.getSession().removeAttribute(sessionAttributeKey);
            } else {
                // 验证码不匹配
                throw new CaptchaException("验证码输入错误");
            }
        }
    }

还是看不出来啥问题,你可以试试看用拦截器实现。拦截器,拦截固定的路径,不用每次都去执行遍历判断是否是要验证的url。配合自定义注解,可以更灵活的控制验证行为。通过异常处理器来提示客户端验证码错误。

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
		Captcha captcha = handlerMethod.getMethodAnnotation(Captcha.class);
		if (captcha == null) {
			return Boolean.TRUE;
		}
		
		String code = request.getParameter(captcha.value());
		if (!StringUtils.isEmpty(code)) { // 验证码参数非空
			HttpSession session = request.getSession(Boolean.FALSE);
			if (session != null) { 
				Object attr = session.getAttribute(SessionKeys.CAPTCHA);
				if (attr != null && code.equalsIgnoreCase((String) attr)) {
					if (captcha.invalidateSession()) {
						session.invalidate(); // 验证ok,失效会话
					}
					return Boolean.TRUE;
				}
			}
		}
		throw new ServiceException(Message.fail(HttpStatus.BAD_REQUEST, "验证码错误"));
	}

也许你可以试试看 :smiley:

OK,我试试看,谢谢了~:smile:

1 个赞

不好意思,我知道错误在哪了,不是RESTful出了问题,是在转发的时候出了问题,:sob:感谢 KevinBlandy的支持,非常抱歉耽误您的时间。

1 个赞