Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 拦截@RequestHeader异常以查找缺少的标头_Java_Spring_Spring Mvc_Servlets - Fatal编程技术网

Java 拦截@RequestHeader异常以查找缺少的标头

Java 拦截@RequestHeader异常以查找缺少的标头,java,spring,spring-mvc,servlets,Java,Spring,Spring Mvc,Servlets,例如,我在控制器中有一个带有has参数的方法 @RequestMapping(value = "/{blabla}", method = RequestMethod.POST) @ResponseStatus(HttpStatus.CREATED) public void post(@RequestHeader("ETag") int etag) 若请求中并没有ETag头,则client gets 400(BAD_请求),这并没有任何信息。 我需要以某种方式处理这个异常,并将我自己的异常发送给

例如,我在控制器中有一个带有has参数的方法

@RequestMapping(value = "/{blabla}", method = RequestMethod.POST)
@ResponseStatus(HttpStatus.CREATED)
public void post(@RequestHeader("ETag") int etag)
若请求中并没有ETag头,则client gets 400(BAD_请求),这并没有任何信息。 我需要以某种方式处理这个异常,并将我自己的异常发送给客户机(为此我使用JSON)。 我知道我可以通过@ExceptionHandler截获异常,但在这种情况下,所有HTTP 400请求都将得到处理,但我希望头中缺少ETag。
有什么想法吗?

有两种方法可以实现你正在尝试的目标

首先将
@RequestHeader
required
false

@RequestMapping(value = "/{blabla}", method = RequestMethod.POST)
@ResponseStatus(HttpStatus.CREATED)
public void post(@RequestHeader(value="ETag", required=false) String ETag) {
    if(ETag == null) {
        // Your JSON Error Handling
    } else {
        // Your Processing
    }
}
第二次使用
HttpServletRequest
而不是
@RequestHeader

@RequestMapping(value = "/{blabla}", method = RequestMethod.POST)
@ResponseStatus(HttpStatus.CREATED)
public void post(HttpServletRequest request) {
    String ETag = request.getHeader("ETag");
    if(ETag == null) {
        // Your JSON Error Handling
    } else {
        // Your Processing
    }
}

如果您不想在请求映射中处理这个问题,那么可以创建一个Servlet过滤器,并在过滤器中查找ETag头。如果不存在,则抛出异常。这将仅适用于与筛选器的URL映射匹配的请求

public final class MyEtagFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String etag = request.getHeader("ETag");

        if(etag == null)
            throw new MissingEtagHeaderException("...");

        filterChain.doFilter(request, response);
    }
}

您必须实现自己的MissingEtagHeaderException,或使用其他一些现有的异常。

您应该使用@ExceptionHandler方法,该方法查看ETag标头是否存在并采取适当的操作:

@ExceptionHandler(UnsatisfiedServletRequestParameterException.class)
public onErr400(@RequestHeader(value="ETag", required=false) String ETag,
        UnsatisfiedServletRequestParameterException ex) {
    if(ETag == null) {
        // Ok the problem was ETag Header : give your informational message
    } else {
        // It is another error 400  : simply say request is incorrect or use ex
    }
}

这是相对简单的。声明两个处理程序方法,一个在
@RequestMapping
headers
属性中声明适当的头,另一个不声明。Spring将根据请求的内容小心地调用相应的请求

@RequestMapping(value = "/{blabla}", method = RequestMethod.POST, headers = "ETag")
@ResponseStatus(HttpStatus.CREATED)
public void postWith(@RequestHeader("ETag") int etag) {
    // has it
}

@RequestMapping(value = "/{blabla}", method = RequestMethod.POST)
@ResponseStatus(HttpStatus.CREATED)
public void postWithout() {
    // no dice
    // custom failure response
}

编写一个带有注释@ExceptionHandler的方法,并使用ServletRequestBindingException.class,因为在缺少标头的情况下会引发此异常

例如:

@ExceptionHandler(ServletRequestBindingException.class)
public ResponseEntity<ResponseObject> handleHeaderError(){

    ResponseObject responseObject=new ResponseObject();
    responseObject.setStatus(Constants.ResponseStatus.FAILURE.getStatus());
    responseObject.setMessage(header_missing_message);

    ResponseEntity<ResponseObject> responseEntity=new ResponseEntity<ResponseObject>(responseObject, HttpStatus.BAD_REQUEST);
    return responseEntity;
}
@ExceptionHandler(ServletRequestBindingException.class)
公共响应处理错误(){
ResponseObject ResponseObject=新的ResponseObject();
responseObject.setStatus(Constants.ResponseStatus.FAILURE.getStatus());
responseObject.setMessage(标头\缺少\消息);
ResponseEntity ResponseEntity=新的ResponseEntity(responseObject,HttpStatus.BAD_请求);
返回响应性;
}

您也可以通过使用spring中的注释
@ControllerAdvice
来实现这一点

@ControllerAdvice
public class ExceptionHandler extends ResponseEntityExceptionHandler{

    /**
     * Handle ServletRequestBindingException. Triggered when a 'required' request
     * header parameter is missing.
     *
     * @param ex      ServletRequestBindingException
     * @param headers HttpHeaders
     * @param status  HttpStatus
     * @param request WebRequest
     * @return the ResponseEntity object
     */
    @Override
    protected ResponseEntity<Object> handleServletRequestBindingException(ServletRequestBindingException ex,
            HttpHeaders headers, HttpStatus status, WebRequest request) {
        return new ResponseEntity<>(ex.getMessage(), headers, status);
    }

}
@ControllerAdvice
公共类ExceptionHandler扩展了ResponseEntityExceptionHandler{
/**
*处理ServletRequestBindingException。在“必需”请求时触发
*缺少标头参数。
*
*@param ex ServletRequestBindingException
*@param headers-HttpHeaders
*@param status HttpStatus
*@param request WebRequest
*@返回ResponseEntity对象
*/
@凌驾
受保护的响应handleServletRequestBindingException(ServletRequestBindingException ex,
HttpHeaders标头、HttpStatus状态、WebRequest请求){
返回新的ResponseEntity(例如getMessage()、标题、状态);
}
}
当您访问API而不使用所需的请求标头时,响应为:

字符串类型的方法参数缺少请求标头“Authorization”


与此异常类似,您可以自定义所有其他异常。

您也可以拦截异常,而无需扩展
ResponseEntityExceptionHandler

@ControllerAdvice
public class ControllerExceptionHandler {

    @ExceptionHandler(ServletRequestBindingException.class)
    @ResponseBody
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public ResponseEntity<Object> handleServletRequestBindingException(ServletRequestBindingException ex) {
        // return a ResponseEntity<Object> object here.
    }
}
@RestControllerAdvice
public class ValidationHandler extends ResponseEntityExceptionHandler {

  @ExceptionHandler(value = {
      MissingRequestHeaderException.class,
      InvalidRequestHeaderException.class
  })
  protected ResponseEntity<Object> handleRequestHeaderException(Exception ex) {
    log.error(ex.getMessage());
    return ResponseEntity.badRequest().body(ErrorResponse.builder()
        .status(String.valueOf(HttpStatus.BAD_REQUEST.value()))
        .reason(ex.getMessage()).build());
  }


  @AllArgsConstructor
  @Getter
  @Builder
  public static class ErrorResponse {

    private String status;
    private String reason;
  }
}
@ControllerAdvice
公共类ControllerExceptionHandler{
@ExceptionHandler(ServletRequestBindingException.class)
@应答器
@ResponseStatus(HttpStatus.BAD_请求)
公共响应性handleServletRequestBindingException(ServletRequestBindingException ex){
//在此处返回ResponseEntity对象。
}
}

如果Spring版本为5+,则需要处理的确切异常是
MissingRequestHeaderException
。如果全局异常处理程序类扩展了
ResponseEntityExceptionHandler
,那么为
ServletRequestBindingException
添加
@ExceptionHandler
将无法工作,因为
MissingRequestHeaderException
扩展了
ServletRequestBindingException
,后者在
handleException
方法的
ResponseEntityExceptionHandler
。如果您尝试,您将获得映射到…异常的
不明确@ExceptionHandler方法。

您可以将
@Nullable
添加到此请求参数,如果不存在,请求仍会进入控制器,而不会抛出
MissingRequestHeaderException
,您还可以添加手动验证,以便在控制器中抛出您喜欢的内容,并在ExceptionHandler中处理。

您可以创建一个自定义异常类,例如,
InvalidRequestHeaderException.java
。您可以在此处自定义例外消息

@ResponseStatus(HttpStatus.BAD_REQUEST)
public class InvalidRequestHeaderException extends RuntimeException {

  public InvalidRequestHeaderException() {
    super("Invalid request header provided.");
  }
}
在控制器中,如果提供的标头无效,则可以引发异常

@RequestMapping(value = "/{blabla}", method = RequestMethod.POST)
@ResponseStatus(HttpStatus.CREATED)
public void post(@RequestHeader("ETag") int etag) {
  // some code
  
  if (!isSupportedPlatform(platform)) {
    throw new InvalidRequestHeaderException();
  }
  
  // some code
}
然后可以创建ValidationHandler.java来处理这些异常

@RestControllerAdvice
public class ValidationHandler extends ResponseEntityExceptionHandler {

  @ExceptionHandler(value = {
      MissingRequestHeaderException.class,
      InvalidRequestHeaderException.class
  })
  protected ResponseEntity<Object> handleRequestHeaderException(Exception ex) {
    log.error(ex.getMessage());
    return ResponseEntity.badRequest().body(ErrorResponse.builder()
        .status(String.valueOf(HttpStatus.BAD_REQUEST.value()))
        .reason(ex.getMessage()).build());
  }


  @AllArgsConstructor
  @Getter
  @Builder
  public static class ErrorResponse {

    private String status;
    private String reason;
  }
}
@RestControllerAdvice
公共类ValidationHandler扩展了ResponseEntityExceptionHandler{
@ExceptionHandler(值={
MissingRequestHeaderException.class,
InvalidRequestHeaderException.class无效
})
受保护的响应HandlerRequestHeaderException(异常ex){
log.error(例如getMessage());
返回ResponseEntity.badRequest().body(ErrorResponse.builder())
.status(String.valueOf(HttpStatus.BAD_REQUEST.value()))
.reason(例如getMessage()).build());
}
@AllArgsConstructor
@吸气剂
@建筑商
公共静态类错误响应{
私有字符串状态;
私有字符串原因;
}
}
通过使用
MissingRequestHeaderException
,如果您用
@RequestHeader
注释的内容丢失,它将引发异常,因此您将得到如下异常:

int类型的方法参数缺少请求标头“Etag”

当请求标头存在但无效时,将引发此异常:

提供的请求标头无效


在Spring5+中,就这么简单<代码>错误响应