【问题标题】:How to return proper error response for content-type text/csv?如何为内容类型文本/csv 返回正确的错误响应?
【发布时间】:2017-11-16 15:59:55
【问题描述】:

我有一个 servlet,通常我会返回 text/csv 作为响应。所以一个普通的逗号分隔字符串。

但是:如果出现异常,我只想显示一些错误文本作为响应。但是 Spring 会生成一个自定义的 ResponseEntity 对象,然后尝试将此响应转换为显然失败的 csv。

是否可以将请求的格式替换为format=json,然后只返回默认的Spring错误响应?

@RestController
public class CsvServlet {

    @RequestMapping(value = "/test", produces = "text/csv")
    @ResponseBody
    public String errorCsv(HttpServletRequest request) {
        return "some, plain, text";
    }
}

用法:localhost:8080/test?format=csv

当拥有spring.security.enabled=true 时,这将首先验证基本身份验证凭据。如果失败,spring 会自动重定向到/error servlet。

因此BasicErrorController.error() 方法进入,捕获错误并生成带有timestamp, exception, path, etc 等错误属性的ResponseEntity

问题:现在返回 ResponseEntity 类型的 Object。只要格式参数是?format=json/xml,这很好。因为响应可以被正确转换。

但在我的特殊情况下,我请求?format=csv,对话将失败,导致:

无法创建响应: org.springframework.web.HttpMediaTypeNotAcceptableException:不能 找到可接受的代表

这部分正确,而且具有误导性,因为用户应该直接看到身份验证凭据无效。因为一般我接受csv,但Spring 和映射器不知道如何将ResponseEntity 转换为像csv 这样的普通格式。

问题:如何保留原始异常?这样我就可以返回纯文本错误消息。在这种情况下,如果我可以返回 application/json 响应也很好!

【问题讨论】:

  • 您是否尝试使用@ControllerAdvice 添加 ExecptionHandlerAdvice?
  • 是的,但这只会捕获HttpMediaTypeNotAcceptableException,而不是BadCredentialsException(如上所述,BasicErrorController 会捕获)。

标签: java json spring csv spring-mvc


【解决方案1】:

暂时如下解决方法:覆盖/error servlet 处理程序,如果?format 参数不是json/xml,则返回原始http 状态错误,不带正文。

因此,spring 无法将正文转换为纯格式并正确返回响应(但正文中没有异常详细信息)。

@Controller
public class WorkaroundBasicErrorController extends BasicErrorController {
    //default constructor from ErrorMvcAutoConfiguration
    public DefaultBasicErrorController(ErrorAttributes errorAttributes, ServerProperties serverProperties,
                                       ObjectProvider<List<ErrorViewResolver>> errorViewResolversProvider) {
        super(errorAttributes, serverProperties.getError(), errorViewResolversProvider.getIfAvailable());
    }

    @RequestMapping
    @ResponseBody
    @Override
    public ResponseEntity<Map<String, Object>> error(HttpServletRequest request) {
        String format = request.getParameter("format");

        return (StringUtils.containsAny(format, "json", "xml"))
            ? super.error(request)
            : new ResponseEntity<>(getStatus(request)); //neglect body for plain formats
    }
}

【讨论】:

    【解决方案2】:

    尝试使用void @ExceptionHandler,并将错误信息直接写入HttpResponse

    【讨论】:

    • 如上所述,任何@ExceptionHandler 都不会在触发重定向到/error servlet 的异常情况下捕获,例如BadCredentialsException
    猜你喜欢
    • 2010-09-28
    • 1970-01-01
    • 2023-04-10
    • 2011-08-27
    • 1970-01-01
    • 1970-01-01
    • 2021-06-16
    • 1970-01-01
    • 2020-06-10
    相关资源
    最近更新 更多