为了账号安全,请及时绑定邮箱和手机立即绑定

在 Spring 中使用自定义解析器返回 HTTP 状态 BAD_REQUEST

在 Spring 中使用自定义解析器返回 HTTP 状态 BAD_REQUEST

慕森王 2023-03-09 15:32:32
我正在使用Spring Boot 1.5.15开发 REST API 。我已经实施了一个客户HandlerMethodArgumentResolver来映射 HTTP 标头。具体来说,我分配了 HTTP header 的值Some-Header,删除了前缀“XXX”。首先,我定义了一个自定义注解。@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.PARAMETER)public @interface SomeHeader {}然后,我实现了一个自定义解析器。public class SomeHeaderArgumentResolver implements HandlerMethodArgumentResolver {    @Override    public boolean supportsParameter(MethodParameter parameter) {        return parameter.getParameterAnnotation(SomeHeader.class) != null;    }    @Override    public Object resolveArgument(MethodParameter parameter,                                  ModelAndViewContainer mavContainer,                                  NativeWebRequest webRequest,                                  WebDataBinderFactory binderFactory) {        HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest();        final String headerValue = request.getHeader("Some-Header");        return headerValue.replace("XXX ", "");    }}最后,我让 Spring 知道配置类中的解析器。@Configurationpublic class WebMvcConfig extends WebMvcConfigurerAdapter {    @Override    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {        argumentResolvers.add(new SomeHeaderArgumentResolver());    }}现在,我可以在我需要的任何控制器中使用以下映射。@PostMapping("/some/paath")public void someMethod(@SomeHeader String someHeaderValue) {   // Method body...}但是,Some-Header信息对我来说是强制性的。我希望如果它不存在,Spring 会向调用者返回 400 Bad Request 响应。这与我使用注释可以获得的行为相同@RequestHeader("Some-Header")。我可以复制相同的行为吗?可能,我不想使用专用的控制器建议。
查看完整描述

3 回答

?
拉风的咖菲猫

TA贡献1995条经验 获得超2个赞

您可以为任何情况声明自己的异常,并在控制器中设置 ExceptionHandler 以返回正确的 http-status。


@ResponseStatus(HttpStatus.BAD_REQUEST)

@ExceptionHandler({SameHeaderException.class})

public Object onSameHeaderException(SameHeaderException e) {

    return ImmutableMap.of("reason", e.getMessage());

}

因此,如果标头不存在,您可以抛出此异常:


if (someHeaderValue == null) { throw new SameHeaderException(); }


查看完整回答
反对 回复 2023-03-09
?
茅侃侃

TA贡献1842条经验 获得超21个赞

RequestHeaderMethodArgumentResolver如果您看到which is used for的实现,您将看到抽象类方法@RequestHeader的重写实现,如下所示:handleMissingValueAbstractNamedValueMethodArgumentResolver


@Override

protected void handleMissingValue(String name, MethodParameter parameter) throws ServletRequestBindingException {

        throw new ServletRequestBindingException("Missing request header '" + name +

                "' for method parameter of type " + parameter.getNestedParameterType().getSimpleName());

}

该handleMissingValue方法用于resolveArgument的方法中AbstractNamedValueMethodArgumentResolver,它RequestHeaderMethodArgumentResolver根据某些条件进行扩展。因此,当标头不存在并ServletRequestBindingException抛出时,SpringDefaultHandlerExceptionResolver将处理该问题并发送400响应。


这就是验证在@RequestHeader. resolveArgument所以你可以在你的类的方法中实现类似的东西,SomeHeaderArgumentResolver如下所示:


public class SomeHeaderArgumentResolver implements HandlerMethodArgumentResolver {

    @Override

    public boolean supportsParameter(MethodParameter parameter) {

        return parameter.getParameterAnnotation(SomeHeader.class) != null;

    }


    @Override

    public Object resolveArgument(MethodParameter parameter,

                                  ModelAndViewContainer mavContainer,

                                  NativeWebRequest webRequest,

                                  WebDataBinderFactory binderFactory) {

        HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest();

        final String headerValue = request.getHeader("Some-Header");

        if(headerValue != null){

           return headerValue.replace("XXX ", "");

        } else {

           //handle scenario if header absent with ServletRequestBindingException

        }

       }

    }


查看完整回答
反对 回复 2023-03-09
?
富国沪深

TA贡献1790条经验 获得超9个赞

我明白了扩展哪个类是让 Spring 发挥魔力的正确类。


RequestHeaderMethodArgumentResolverSpring 用来解析 Java 对象中的 HTTP 标头值的类扩展了抽象类AbstractNamedValueMethodArgumentResolver。此类允许您使用createNamedValueInfo方法指定标头值是否具有某些默认值。


所以,它遵循代码。


public class SomeHeaderArgumentResolver extends AbstractNamedValueMethodArgumentResolver {

    @Override

    protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) {

        // The second parameter specifies if the value is required, 

        // and the third if there is some default value.

        return new NamedValueInfo("", true, null);

    }


    @Override

    protected Object resolveName(String name, 

                                 MethodParameter parameter, 

                                 NativeWebRequest request) {

        final String headerValue = request.getHeader("Some-Value");

        if (StringUtils.isEmpty(headerValue)) {

            // Returning null tells Spring that there is no value for the parameter

            return null;

        }

        return headerValue.replace("XXX ", "");

    }


    @Override

    public boolean supportsParameter(MethodParameter parameter) {

        return (parameter.hasParameterAnnotation(SomeHeader.class) &&

                !Map.class.isAssignableFrom(

                    parameter.nestedIfOptional().getNestedParameterType()));

    }

}

我唯一不喜欢的是我正在使用为处理命名值而开发的结构,但我没有命名值。


希望能帮助到你。


查看完整回答
反对 回复 2023-03-09
  • 3 回答
  • 0 关注
  • 119 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信