Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/334.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-core/3.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 Spring MVC 3.2-错误页面的内容协商?_Java_Spring_Spring Mvc_Content Negotiation - Fatal编程技术网

Java Spring MVC 3.2-错误页面的内容协商?

Java Spring MVC 3.2-错误页面的内容协商?,java,spring,spring-mvc,content-negotiation,Java,Spring,Spring Mvc,Content Negotiation,为了全局处理控制器外部可能发生的错误(如HTTP 404),我在我的web.xml中有如下类似的条目: <error-page> <error-code>404</error-code> <location>/errors/404</location> </error-page> 404 /错误/404 在我的ErrorController中,我有类似以下的相应方法: @Controller @Requ

为了全局处理控制器外部可能发生的错误(如HTTP 404),我在我的web.xml中有如下类似的条目:

<error-page>
    <error-code>404</error-code>
    <location>/errors/404</location>
</error-page>

404
/错误/404
在我的ErrorController中,我有类似以下的相应方法:

@Controller
@RequestMapping("/errors")
public class ErrorController {

    @RequestMapping(value = "/404", method = RequestMethod.GET)
    @ResponseBody
    public ResponseEntity<ErrorResponse> error404() {

        ErrorResponse errorBody = new ErrorResponse(404, "Resource Not Found!");

        return new ResponseEntity<ErrorResponse>(errorBody, HttpStatus.NOT_FOUND);
    }
}
@控制器
@请求映射(“/errors”)
公共类错误控制器{
@RequestMapping(value=“/404”,method=RequestMethod.GET)
@应答器
公共响应错误404(){
ErrorResponse errorBody=新的ErrorResponse(404,“未找到资源!”);
返回新的响应属性(errorBody,HttpStatus.NOT_FOUND);
}
}
我面临的问题是,我配置的
ContentNegotiationManager
和消息转换器没有在本例中使用。我怀疑,由于请求被重定向到错误页面,在内容协商中使用的原始请求属性丢失,这被视为一个完全独立的请求。(即原始请求/mycontroller/badrource.json-->/errors/404(无文件扩展名))


在这样的错误处理程序中,是否有任何方法可以确定和/或响应原始请求中请求的适当内容类型?

是的,应用程序异常和HTTP响应错误代码是两种不同的东西

您可以像下面这样修改代码,这样您就可以访问
requestUri
。 我想你可以根据它找到内容类型。我知道它很粗糙,但我认为我们没有其他解决方案:

@RequestMapping(value = "/404", method = RequestMethod.GET)
@ResponseBody
public ResponseEntity<ErrorResponse> error404(HttpServletRequest request) {

    ErrorResponse errorBody = new ErrorResponse(404, "Resource Not Found!");

    String requestUri = request.getRequestURI();

    return new ResponseEntity<ErrorResponse>(errorBody, HttpStatus.NOT_FOUND);
}
@RequestMapping(value=“/404”,method=RequestMethod.GET)
@应答器
公共响应错误404(HttpServletRequest请求){
ErrorResponse errorBody=新的ErrorResponse(404,“未找到资源!”);
String requestUri=request.getRequestURI();
返回新的响应属性(errorBody,HttpStatus.NOT_FOUND);
}

从这个示例中,我假定您的应用程序是REST服务,那么您可能可以在REST完整服务中引用。

我对此提出了一些建议,但似乎有效。它基本上在错误处理中包含一个额外的转发,以确定原始请求的文件扩展名

在my web.xml中,我将错误转发到一个中间操作:

<error-page>
    <error-code>404</error-code>
    <location>/errors/redirect</location>
</error-page>

404
/错误/重定向
然后,在转发到将生成错误响应的操作之前,检查原始请求上是否有文件扩展名。如果有,它将确保将其附加到转发URI。HTTP头会自动转发,因此如果您设置的内容协商只涉及文件扩展名或HTTP头,这将有效地允许“错误页”以适当的内容类型返回错误

@Controller
@RequestMapping("/errors")
public class ErrorController {

    @RequestMapping(value = "/redirect", method = RequestMethod.GET)
    public void errorRedirect(HttpServletRequest request, HttpServletResponse response) {

        // Get original request URI
        String uri = (String)request.getAttribute(WebUtils.ERROR_REQUEST_URI_ATTRIBUTE);

        // Try to determine file extension
        String filename = WebUtils.extractFullFilenameFromUrlPath(uri);
        String extension = StringUtils.getFilenameExtension(filename);
        extension = StringUtils.hasText(extension) ? "." + extension : "";

        // Forward request to appropriate handler with original request's file extension (i.e. /errors/404.json)
        String forwardUri = "/errors/404" + extension); 
        request.getRequestDispatcher(forwardUri).forward(request, response);
    }

    @RequestMapping(value = "/404", method = RequestMethod.GET)
    @ResponseBody
    public ResponseEntity<ErrorResponse> error404() {

        ErrorResponse errorBody = new ErrorResponse(404, "Resource Not Found!");

        return new ResponseEntity<ErrorResponse>(errorBody, HttpStatus.NOT_FOUND);
    }
}
@控制器
@请求映射(“/errors”)
公共类错误控制器{
@RequestMapping(value=“/redirect”,method=RequestMethod.GET)
public void errorRedirect(HttpServletRequest请求、HttpServletResponse响应){
//获取原始请求URI
stringuri=(String)request.getAttribute(WebUtils.ERROR\u request\u uri\u ATTRIBUTE);
//尝试确定文件扩展名
String filename=WebUtils.extractFullFilenameFromUrlPath(uri);
字符串扩展名=StringUtils.getFilenameExtension(文件名);
扩展名=StringUtils.hasText(扩展名)?“+扩展名:”;
//使用原始请求的文件扩展名(即/errors/404.json)将请求转发给相应的处理程序
字符串forwardUri=“/errors/404”+扩展名);
getRequestDispatcher(forwardUri).forward(请求,响应);
}
@RequestMapping(value=“/404”,method=RequestMethod.GET)
@应答器
公共响应错误404(){
ErrorResponse errorBody=新的ErrorResponse(404,“未找到资源!”);
返回新的响应属性(errorBody,HttpStatus.NOT_FOUND);
}
}

Spring MVC 3.2现在包含一个名为
@ControllerAdvice
的有用注释。您可以添加一个
ExceptionHandler
方法,该方法将全局处理您定义的任何异常

对我来说,我只关心返回到客户端的两种可能的内容类型—
application/json
text/html

以下是我将如何设置它-

@ControllerAdvice
public class ExceptionControllerAdvice {

    private static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
    private static final MediaType JSON_MEDIA_TYPE = new MediaType("application", "json", DEFAULT_CHARSET);

    //I decided to handle all exceptions in this one method
    @ExceptionHandler(Throwable.class)
    public @ResponseBody String handleThrowable(HttpServletRequest request, HttpServletResponse response, Throwable ex) throws IOException {

        ...

        if(supportsJsonResponse(request.getHeader("Accept"))) {

            //return response as JSON
            response.setStatus(statusCode);
            response.setContentType(JSON_MEDIA_TYPE.toString());

                    //TODO serialize your error in a JSON format
                    //return ...

        } else {

            //return as HTML
            response.setContentType("text/html");
            response.sendError(statusCode, exceptionMessage);
            return null;
        }
    }

    private boolean supportsJsonResponse(String acceptHeader) {

        List<MediaType> mediaTypes = MediaType.parseMediaTypes(acceptHeader);

        for(MediaType mediaType : mediaTypes) {
            if(JSON_MEDIA_TYPE.includes(mediaType)) {
                return true;
            }
        }

        return false;
    }

}
@ControllerAdvice
公共类例外ControllerAdvice{
私有静态最终字符集DEFAULT_Charset=Charset.forName(“UTF-8”);
私有静态最终MediaType JSON\U MEDIA\U TYPE=新MediaType(“应用程序”、“JSON”、默认字符集);
//我决定用这个方法处理所有异常
@ExceptionHandler(Throwable.class)
public@ResponseBody字符串handleThrowable(HttpServletRequest请求、HttpServletResponse响应、Throwable ex)引发IOException{
...
if(supportsJsonResponse(request.getHeader(“Accept”)){
//以JSON形式返回响应
响应。设置状态(状态代码);
setContentType(JSON_MEDIA_TYPE.toString());
//TODO以JSON格式序列化错误
//返回。。。
}否则{
//以HTML格式返回
response.setContentType(“text/html”);
响应。发送错误(状态代码、异常消息);
返回null;
}
}
私有布尔支持JSONResponse(字符串acceptHeader){
List mediaTypes=MediaType.parseMediaTypes(acceptHeader);
对于(媒体类型媒体类型:媒体类型){
if(JSON_MEDIA_TYPE.includes(mediaType)){
返回true;
}
}
返回false;
}
}

感谢您的输入。我看过那篇文章,但除非我遗漏了什么,否则它只处理来自控制器的异常,而不处理一般的servlet错误。此外,在此上下文中,
request.getRequestURI()
提供错误页面的URI。看起来您必须使用