如何从 Spring 中的 WebRequest 获取请求的 URI?
How to get request's URI from WebRequest in Spring?
我正在 spring Rest 网络服务中使用 @ControllerAdvice
和 ResponseEntityExceptionHandler
处理 REST 异常。到目前为止,一切正常,直到我决定将 URI
路径(发生异常)添加到 BAD_REQUEST 响应中。
@ControllerAdvice
public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
@Override
protected ResponseEntity<Object> handleHttpMessageNotReadable(HttpMessageNotReadableException ex,
HttpHeaders headers, HttpStatus status, WebRequest request) {
logger.info(request.toString());
return handleExceptionInternal(ex, errorMessage(HttpStatus.BAD_REQUEST, ex, request), headers, HttpStatus.BAD_REQUEST, request);
}
private ApiError errorMessage(HttpStatus httpStatus, Exception ex, WebRequest request) {
final String message = ex.getMessage() == null ? ex.getClass().getName() : ex.getMessage();
final String developerMessage = ex.getCause() == null ? ex.toString() : ex.getCause().getMessage();
return new ApiError(httpStatus.value(), message, developerMessage, System.currentTimeMillis(), request.getDescription(false));
}
ApiError 只是一个 Pojo class:
public class ApiError {
private Long timeStamp;
private int status;
private String message;
private String developerMessage;
private String path;
}
但是WebRequest没有给出任何api来获取请求失败的路径。我试过:
request.toString()
returns -> ServletWebRequest: uri=/signup;client=0:0:0:0:0:0:0:1
request.getDescription(false)
returns -> uri=/signup
getDescription
非常接近要求,但不符合要求。有没有办法只获取uri部分?
找到解决方案。将 WebRequest
转换为 ServletWebRequest
解决了这个问题。
((ServletWebRequest)request).getRequest().getRequestURI().toString()
returns 完整路径 - http://localhost:8080/signup
这个问题有多种解决方案。
1) 可以使用 WebRequest 获取请求 URI 和客户端信息
webRequest.getDescription(真).
true 将显示用户的信息,例如客户端 ID,false 将仅打印 URI。
2) 在方法定义中直接使用 HttpServletRequest 而不是 WebRequest as
@Override
protected ResponseEntity<Object> handleHttpMessageNotReadable(HttpMessageNotReadableException ex,
HttpHeaders headers, HttpStatus status, WebRequest request, HttpServletRequest httpRequest) {
logger.info(httpRequest.getRequestURI());
return handleExceptionInternal(ex, errorMessage(HttpStatus.BAD_REQUEST, ex, request), headers, HttpStatus.BAD_REQUEST, request);
}
ResponseEntityExceptionHandler 解释了 @ControllerAdvice class 的方便基础 class 希望在所有 @RequestMapping 中提供集中式异常处理通过@ExceptionHandler 方法的方法。 here
在SpringBoot 2.1.6中,可以这样写:
RestExceptionHandler.java
@Order(Ordered.HIGHEST_PRECEDENCE)
@RestControllerAdvice
public class RestExceptionHandler extends ResponseEntityExceptionHandler {
private static final Logger logger = LoggerFactory.getLogger(RestExceptionHandler.class);
@ExceptionHandler(ResourceNotFoundException.class)
protected ResponseEntity<Object> handleEntityNotFound(ResourceNotFoundException ex, final HttpServletRequest httpServletRequest) {
ApiError apiError = new ApiError(HttpStatus.NOT_FOUND);
apiError.setMessage("Resource not found");
apiError.setDebugMessage(ex.getMessage());
apiError.setPath(httpServletRequest.getRequestURI());
return buildResponseEntity(apiError);
}
private ResponseEntity<Object> buildResponseEntity(ApiError apiError) {
return new ResponseEntity<>(apiError, apiError.getStatus());
}
@Override
protected ResponseEntity<Object> handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
ApiError apiError = new ApiError(HttpStatus.METHOD_NOT_ALLOWED);
apiError.setMessage(ex.getMessage());
apiError.setPath(((ServletWebRequest)request).getRequest().getRequestURI().toString());
logger.warn(ex.getMessage());
return buildResponseEntity(apiError);
}
}
让我们从实现发送错误的简单结构开始:
ApiError.java
public class ApiError {
// 4xx and 5xx
private HttpStatus status;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
private LocalDateTime timestamp;
// holds a user-friendly message about the error.
private String message;
// holds a system message describing the error in more detail.
@JsonInclude(value = Include.NON_EMPTY)
private String debugMessage;
// returns the part of this request's URL
private String path;
@JsonInclude(value = Include.NON_EMPTY)
private List<String> details=new ArrayList<>();
// setters & getters
}
ResourceNotFoundException.java
public class ResourceNotFoundException extends RuntimeException {
private static final long serialVersionUID = 1L;
public ResourceNotFoundException() {
super();
}
public ResourceNotFoundException(String msg) {
super(msg);
}
访问WebRequest对象的属性:
Object obj = webRequest.getAttribute("org.springframework.web.util.UrlPathHelper.PATH", 0)
String uri = String.valueOf(obj);
webRequest.getAttribute(String attributeName, int scope);
// scope can be either:
// 0: request
// 1: session
// valid attribute names can be fetched with call:
String[] attributeNames = webRequest.getAttributeNames(0); //scope is request
有效的属性名称是:
org.springframework.web.util.UrlPathHelper.PATH
org.springframework.web.context.request.async.WebAsyncManager.WEB_ASYNC_MANAGER
org.springframework.web.servlet.HandlerMapping.bestMatchingHandler
org.springframework.web.servlet.DispatcherServlet.CONTEXT
org.springframework.web.servlet.resource.ResourceUrlProvider
characterEncodingFilter.FILTERED
org.springframework.boot.web.servlet.error.DefaultErrorAttributes.ERROR
org.springframework.web.servlet.DispatcherServlet.THEME_SOURCE
org.springframework.web.servlet.DispatcherServlet.LOCALE_RESOLVER
formContentFilter.FILTERED
org.springframework.web.servlet.HandlerMapping.bestMatchingPattern
requestContextFilter.FILTERED
org.springframework.web.servlet.DispatcherServlet.OUTPUT_FLASH_MAP
org.springframework.web.servlet.HandlerMapping.pathWithinHandlerMapping
org.springframework.web.servlet.DispatcherServlet.FLASH_MAP_MANAGER
org.springframework.web.servlet.HandlerMapping.uriTemplateVariables
org.springframework.web.servlet.DispatcherServlet.THEME_RESOLVER
org.springframework.core.convert.ConversionService
您可以使用 request.getDescription(false)。
我正在使用 SpringBoot 2.5.3 和 globalExceptionHandler。
简短的片段。使用“TheCoder”答案并从那里开始。
如果不需要,则不必使用 header、status、... WebRequest 作为输入参数。这只给出了 url 的端点而不是主机名。
@ExceptionHandler(value = NotFound.class)
ResponseEntity<...> httpNotFoundException(NotFound exc, HttpServletRequest req ) {
//use req.getRequestURI();
}
@ExceptionHandler(value = HttpClientErrorException.class)
ResponseEntity<...> httpClientException(HttpClientErrorException exc, HttpServletRequest req ) {
exc.getRawStatusCode() //to get status code
//I am using this to check for 404 and handling here with other stuff instead of using NotFound.class above.
// Use req.getRequestURI();
}
我正在 spring Rest 网络服务中使用 @ControllerAdvice
和 ResponseEntityExceptionHandler
处理 REST 异常。到目前为止,一切正常,直到我决定将 URI
路径(发生异常)添加到 BAD_REQUEST 响应中。
@ControllerAdvice
public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
@Override
protected ResponseEntity<Object> handleHttpMessageNotReadable(HttpMessageNotReadableException ex,
HttpHeaders headers, HttpStatus status, WebRequest request) {
logger.info(request.toString());
return handleExceptionInternal(ex, errorMessage(HttpStatus.BAD_REQUEST, ex, request), headers, HttpStatus.BAD_REQUEST, request);
}
private ApiError errorMessage(HttpStatus httpStatus, Exception ex, WebRequest request) {
final String message = ex.getMessage() == null ? ex.getClass().getName() : ex.getMessage();
final String developerMessage = ex.getCause() == null ? ex.toString() : ex.getCause().getMessage();
return new ApiError(httpStatus.value(), message, developerMessage, System.currentTimeMillis(), request.getDescription(false));
}
ApiError 只是一个 Pojo class:
public class ApiError {
private Long timeStamp;
private int status;
private String message;
private String developerMessage;
private String path;
}
但是WebRequest没有给出任何api来获取请求失败的路径。我试过:
request.toString()
returns -> ServletWebRequest: uri=/signup;client=0:0:0:0:0:0:0:1
request.getDescription(false)
returns -> uri=/signup
getDescription
非常接近要求,但不符合要求。有没有办法只获取uri部分?
找到解决方案。将 WebRequest
转换为 ServletWebRequest
解决了这个问题。
((ServletWebRequest)request).getRequest().getRequestURI().toString()
returns 完整路径 - http://localhost:8080/signup
这个问题有多种解决方案。
1) 可以使用 WebRequest 获取请求 URI 和客户端信息 webRequest.getDescription(真).
true 将显示用户的信息,例如客户端 ID,false 将仅打印 URI。
2) 在方法定义中直接使用 HttpServletRequest 而不是 WebRequest as
@Override
protected ResponseEntity<Object> handleHttpMessageNotReadable(HttpMessageNotReadableException ex,
HttpHeaders headers, HttpStatus status, WebRequest request, HttpServletRequest httpRequest) {
logger.info(httpRequest.getRequestURI());
return handleExceptionInternal(ex, errorMessage(HttpStatus.BAD_REQUEST, ex, request), headers, HttpStatus.BAD_REQUEST, request);
}
ResponseEntityExceptionHandler 解释了 @ControllerAdvice class 的方便基础 class 希望在所有 @RequestMapping 中提供集中式异常处理通过@ExceptionHandler 方法的方法。 here
在SpringBoot 2.1.6中,可以这样写:
RestExceptionHandler.java
@Order(Ordered.HIGHEST_PRECEDENCE)
@RestControllerAdvice
public class RestExceptionHandler extends ResponseEntityExceptionHandler {
private static final Logger logger = LoggerFactory.getLogger(RestExceptionHandler.class);
@ExceptionHandler(ResourceNotFoundException.class)
protected ResponseEntity<Object> handleEntityNotFound(ResourceNotFoundException ex, final HttpServletRequest httpServletRequest) {
ApiError apiError = new ApiError(HttpStatus.NOT_FOUND);
apiError.setMessage("Resource not found");
apiError.setDebugMessage(ex.getMessage());
apiError.setPath(httpServletRequest.getRequestURI());
return buildResponseEntity(apiError);
}
private ResponseEntity<Object> buildResponseEntity(ApiError apiError) {
return new ResponseEntity<>(apiError, apiError.getStatus());
}
@Override
protected ResponseEntity<Object> handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
ApiError apiError = new ApiError(HttpStatus.METHOD_NOT_ALLOWED);
apiError.setMessage(ex.getMessage());
apiError.setPath(((ServletWebRequest)request).getRequest().getRequestURI().toString());
logger.warn(ex.getMessage());
return buildResponseEntity(apiError);
}
}
让我们从实现发送错误的简单结构开始:
ApiError.java
public class ApiError {
// 4xx and 5xx
private HttpStatus status;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
private LocalDateTime timestamp;
// holds a user-friendly message about the error.
private String message;
// holds a system message describing the error in more detail.
@JsonInclude(value = Include.NON_EMPTY)
private String debugMessage;
// returns the part of this request's URL
private String path;
@JsonInclude(value = Include.NON_EMPTY)
private List<String> details=new ArrayList<>();
// setters & getters
}
ResourceNotFoundException.java
public class ResourceNotFoundException extends RuntimeException {
private static final long serialVersionUID = 1L;
public ResourceNotFoundException() {
super();
}
public ResourceNotFoundException(String msg) {
super(msg);
}
访问WebRequest对象的属性:
Object obj = webRequest.getAttribute("org.springframework.web.util.UrlPathHelper.PATH", 0)
String uri = String.valueOf(obj);
webRequest.getAttribute(String attributeName, int scope);
// scope can be either:
// 0: request
// 1: session
// valid attribute names can be fetched with call:
String[] attributeNames = webRequest.getAttributeNames(0); //scope is request
有效的属性名称是:
org.springframework.web.util.UrlPathHelper.PATH
org.springframework.web.context.request.async.WebAsyncManager.WEB_ASYNC_MANAGER
org.springframework.web.servlet.HandlerMapping.bestMatchingHandler
org.springframework.web.servlet.DispatcherServlet.CONTEXT
org.springframework.web.servlet.resource.ResourceUrlProvider
characterEncodingFilter.FILTERED
org.springframework.boot.web.servlet.error.DefaultErrorAttributes.ERROR
org.springframework.web.servlet.DispatcherServlet.THEME_SOURCE
org.springframework.web.servlet.DispatcherServlet.LOCALE_RESOLVER
formContentFilter.FILTERED
org.springframework.web.servlet.HandlerMapping.bestMatchingPattern
requestContextFilter.FILTERED
org.springframework.web.servlet.DispatcherServlet.OUTPUT_FLASH_MAP
org.springframework.web.servlet.HandlerMapping.pathWithinHandlerMapping
org.springframework.web.servlet.DispatcherServlet.FLASH_MAP_MANAGER
org.springframework.web.servlet.HandlerMapping.uriTemplateVariables
org.springframework.web.servlet.DispatcherServlet.THEME_RESOLVER
org.springframework.core.convert.ConversionService
您可以使用 request.getDescription(false)。
我正在使用 SpringBoot 2.5.3 和 globalExceptionHandler。 简短的片段。使用“TheCoder”答案并从那里开始。 如果不需要,则不必使用 header、status、... WebRequest 作为输入参数。这只给出了 url 的端点而不是主机名。
@ExceptionHandler(value = NotFound.class)
ResponseEntity<...> httpNotFoundException(NotFound exc, HttpServletRequest req ) {
//use req.getRequestURI();
}
@ExceptionHandler(value = HttpClientErrorException.class)
ResponseEntity<...> httpClientException(HttpClientErrorException exc, HttpServletRequest req ) {
exc.getRawStatusCode() //to get status code
//I am using this to check for 404 and handling here with other stuff instead of using NotFound.class above.
// Use req.getRequestURI();
}