【问题标题】:Spring Rest Service that returns different media type based on logic基于逻辑返回不同媒体类型的 Spring Rest Service
【发布时间】:2015-04-14 13:34:33
【问题描述】:

帮助!我已经尽我所能,但似乎没有任何效果。我的问题如下:

我有一个 Spring REST 服务,它发出一个 REST 调用,接收一个 base64 编码的 PDF。然后我解码 PDF,并在浏览器中显示它。我可以让这部分完美地工作!但!我在处理 404、500 等时遇到问题。错误消息。

不幸的是,错误消息在 API 中作为哈希映射中的消息返回给我,正如您在下面的逻辑中看到的那样。

我尝试创建 PDF,但无法将其转换为文件对象,我尝试将字节直接流式传输到浏览器,但无论我做什么,它都不适合我。

有没有办法根据逻辑更改响应标头?成功时返回pdf,出错时返回文本文件给浏览器?

我在这里筋疲力尽,不知道该去哪里。任何建议或指示将不胜感激。

我也尝试向浏览器抛出 404,但它需要一个 pdf 文件,我收到 MIME 错误。

@Controller
@Path("/mon")
public class WSController {

    @Autowired
    Service service;

    @GET
    @Produces("application/pdf")
    @Path("/ws")
    public File getWs(@QueryParam("vin") String vin) throws IOException, URISyntaxException {
        Map response = service.getWs(vin);
        if (response == null) {
            return createErrorFile("Server Error, please try again later.");
        } else if (response.get("ErrorCode") != null && response.get("ErrorCode").equals("E")) {
            return createErrorFile((String) response.get("ErrorDescription"));
        } else {
            return decodeBase64(((String) response.get("Base64String")).replace("\n",""));
        }
    }

    private File decodeBase64(String encodedFile) throws IOException {
        byte[] decodedBytes = DatatypeConverter.parseBase64Binary(encodedFile);

        File file = new File("wS.pdf");
        FileOutputStream fop = new FileOutputStream(file);

        fop.write(decodedBytes);
        fop.flush();
        fop.close();

        return file;
    }

    private File createErrorFile(String errorDescription) throws IOException {
        //Not sure what to do here
        return null;
    }

编辑:这就是最终为我工作的东西。非常感谢您的建议。这是一次美妙的学习经历。

@GET
@Path("/ws")
public Response getWS(@QueryParam("vin") String vin) throws IOException, URISyntaxException {
    Map results = Service.getWS(vin);
    if (results == null) {
        Response.ResponseBuilder rBuild = Response.status(Response.Status.BAD_REQUEST);
        return rBuild.type(MediaType.TEXT_PLAIN)
                .entity("Server error, please try again later.")
                .build();
    } else if (results.get("ErrorCode") != null && results.get("ErrorCode").equals("E")) {
        Response.ResponseBuilder rBuild = Response.status(Response.Status.BAD_REQUEST);
        return rBuild.type(MediaType.TEXT_PLAIN)
                .entity(results.get("ErrorDescription"))
                .build();
    } else {
        File responseData = decodeBase64(((String) results.get("Base64String")).replace("\n", ""));
        Response.ResponseBuilder rBuild = Response.ok(responseData, "application/pdf");
        return rBuild.build();
    }
}

【问题讨论】:

  • 发生错误时,您不能将响应重定向到另一个 URL 位置吗?
  • 我也对此进行了调查。 (sendRedirect(request, response, targetUrl)) 但我不确定最好的方法是获取请求/响应对象。

标签: java spring rest spring-mvc jax-rs


【解决方案1】:

我看到您在帖子中提到的一些问题,但我只阅读了这些实际问题

有没有办法根据逻辑更改响应标头?成功时返回pdf,出错时返回文本文件给浏览器?

所以我会解决他们。我自己,我更喜欢总是返回Response。您可以在那里设置所有标题,以及更多内容。例如

@GET
public Response getSomething() {
    ...
    Response.ResponseBuilder builder = Response.status(200);
    Response response = builder.entity(file)
                               .header("Content-Type", "someType")
                               .build();
    return response;
}

entity(...) 是您通常作为实体主体返回的内容。

  • 另请参阅Response.ResponseBuilder 的 API。 Response 中的大多数静态方法都返回 Response.ResponseBuilder,这就是构建请求的许多选项。

就您的方法中未处理的异常而言,您可以对ExceptionMapper(s) 进行正确处理以处理不同的异常。见here。您可以从映射器返回Response

您可以编写自定义WebApplicationException(s),以免因异常响应构建而使您的代码混乱。然后抛出那个异常。 JAX-RS 已经内置了一种机制来处理异常。您可以使用内置的Response 创建异常。该链接有一个例外。处理异常有很多不同的选项。

【讨论】:

  • 返回一个 Response 对象是更好的做法吗?好像如果你可以控制标题、正文等这些方式,可能会更好一点。
  • 这是偏好。还有其他设置标题的方法。但既然实用程序在那里,为什么不使用它。你可以注入 HttpServletResponse,但我不喜欢这样。对我来说,响应看起来更干净。使用 Response 可以做的不仅仅是标题。看看所有的 Response.ResponseBuilder 方法。身体也没有任何变化。就像您返回文件一样。 Response 只是一个完整的 http 响应的中间包装器
  • 谢谢。这正是我所做的。我会在 OP 中发布我的固定代码。
【解决方案2】:

不要惊慌 :-) 您可以通过向 spring 请求 HttpServletResponse 对象来实现对响应的完全控制。您可以设置响应的 MIME 类型或设置错误代码:

@GET
@Produces("application/pdf")
@Path("/ws")
public void getWs(@QueryParam("vin") String vin, HttpServletRequest request) {
...
...
request.setContentType("text/html");
...

【讨论】:

  • 会设置这样的标题覆盖我的注释吗?我现在正在尝试这个实现。会告诉你进展如何。
  • 可以肯定的是,您应该删除 `@Produces' 并明确设置 MIME 类型。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-15
  • 2021-12-21
  • 2011-01-25
  • 1970-01-01
  • 2018-09-26
  • 1970-01-01
相关资源
最近更新 更多