12

コントローラの外部で発生する可能性のあるエラー(HTTP 404など)をグローバルに処理するために、web.xmlに次のようなエントリがあります。

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

私の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);
    }
}

私が直面している問題はContentNegotiationManager、この場合、構成したメッセージコンバーターとメッセージコンバーターが使用されていないことです。リクエストがエラーページにリダイレクトされているため、コンテンツネゴシエーションで使用されていた元のリクエストの属性が失われ、これは完全に別個のリクエストとして扱われると思われます。(つまり、/ mycontroller / badresource.json-> / errors / 404(ファイル拡張子なし)の元のリクエスト)

このようなエラーハンドラーで、元のリクエストでリクエストされた適切なコンテンツタイプを決定および/または応答する方法はありますか?

4

3 に答える 3

3

これにはちょっとしたハックを思いつきましたが、うまくいくようです。基本的に、元のリクエストのファイル拡張子を特定するために、エラー処理に余分な転送が含まれます。

私の web.xml では、中間アクションに転送されたエラーがあります。

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

次に、エラー応答を生成するアクションに転送する前に、元の要求にファイル拡張子があったかどうかを確認するためにチェックが行われます。存在する場合は、それが確実に転送 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);
    }
}
于 2013-02-07T22:04:19.963 に答える
2

はい、確かに、アプリケーション例外と HTTP 応答エラー コードは 2 つの異なるものです。

にアクセスできるように、以下のようにコードを変更できます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);
}

この例から、あなたのアプリケーションは REST サービスであると推測されます。おそらく、REST フル サービスで404 がどのように処理されるかについて、このリンクを参照できます。

于 2013-02-06T11:43:25.423 に答える