【问题标题】:Jersey: Reading Content-Type:plain/text response as XML泽西岛:阅读 Content-Type:plain/text 响应为 XML
【发布时间】:2023-03-22 17:15:01
【问题描述】:

我收到来自外部服务器的 HTTP 响应,其中包含 XML 的正文。

但是,响应标头显示Content-Type:plain/text

这是不正确的,应该是application/xml。但是,正如我所说,它是一个我们无法更改的外部服务器。

以下代码报错:

ClientResponse response = Client.create().resource(url).get(ClientResponse.class);
return response.getEntity(XmlResponse.class);

例外:

com.sun.jersey.api.client.ClientHandlerException:消息体 Java 类 com.evs.ats.XmlResponse 和 Java 类型类的阅读器 com.evs.ats.XmlResponse,未找到 MIME 媒体类型 text/plain

以下代码有效,但我不喜欢它:

String resultString = response.getEntity(String.class);
InputStream stream = new ByteArrayInputStream(
    resultString.getBytes(StandardCharsets.UTF_8)
);
JAXBContext jc = JAXBContext.newInstance(XmlResponse.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
return (XmlResponse) unmarshaller.unmarshal(stream);

有什么方法可以“强制”泽西岛将其读作XML 吗?还是我唯一的选择是使用JAXB(如上)手动解组它?还是有其他选择?

【问题讨论】:

  • 哪个版本的球衣?
  • <groupId>com.sun.jersey</groupId> <artifactId>jersey-client</artifactId> <version>1.8</version>

标签: java xml jaxb jersey mime-types


【解决方案1】:

如果您要连接的上游服务器在Content-Type HTTP 标头字段中返回错误的值,并且无法“合理化”(修复返回的值),除了没有其他方法(AFAIK)提供您自己的 MessageBodyReader 自定义实现。

使用 Jersey 2 的一种方法是:

public class TextAsXmlMessageBodyReader implements MessageBodyReader<Object> {

    @Override
    public boolean isReadable(Class<?> type, Type genericType,
            Annotation[] annotations, MediaType mediaType) {
        return mediaType.getType().equals("text")
                && mediaType.getSubtype().equals("plain");
    }

    @Override
    public Object readFrom(Class<Object> type, Type genericType,
            Annotation[] annotations, MediaType mediaType,
            MultivaluedMap<String, String> httpHeaders,
            InputStream entityStream) throws IOException, WebApplicationException {
        try {
            final JAXBContext jc = JAXBContext.newInstance(type);
            final Unmarshaller unmarshaller = jc.createUnmarshaller();

            return unmarshaller.unmarshal(entityStream);
        } catch (JAXBException e) {
            throw new WebApplicationException("Error while unmarshalling the response.", e);
        }
    }
}

然后只需向您正在使用的 Jersey 客户端注册这个类。如果您在整个应用程序中使用相同的客户端实例,则可以为每个目标注册自定义消息正文阅读器(因此,如果您碰巧有其他上游服务器,它将不会用于来自其他“正常”服务器的响应您正在与之通信)。注册目标示例:

return ClientBuilder.newClient()  // Get a client; does not have to be a *new* client
        .target(url)              // Target the client to the particular upstream URL
        .register(TextAsXmlMessageBodyReader.class)  // Register the reader as described
        .request()                // Start building a request
        .get(XmlResponse.class);  // Issue a GET request (can be any HTTP method actually)

拥有自定义阅读器实现的优点是可以编写漂亮的流线型代码,专注于配置和发出请求、获取响应以及在需要时进行处理。此外,如果您需要针对目标服务器上的不同资源发出请求(并且它们都指定了错误的Content-Type),则可以重用读取器实现。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-06
    • 1970-01-01
    • 1970-01-01
    • 2011-08-02
    • 1970-01-01
    相关资源
    最近更新 更多