java - 如何在 Jersey 客户端中读取有效负载

标签 java jax-rs jersey-client

我这里有一个小问题。触发请求时,我想使用 HMAC 对整个消息进行签名,并将生成的签名添加到 header 中。

所以我实现了

javax.ws.rs.ext.WriterInterceptorContext

public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException

方法我无法访问实体的字符串表示形式。它总是返回一个空字符串。原因似乎是 MessageBodyWriter 在 WriterInterceptor 之后执行。

基本上我有以下两种失败的情况:

public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException {
    try {
        final ClientOutputStream stream = (ClientOutputStream) requestContext.getProperty(HTTPCLIENT_ENTITY_STREAM);
        String payload = stream.getString(Charset.forName("UTF-8")); // returns alway empty String
        String signature = doSomeSuffWithPayload(payload);

        MultivaluedMap<String, Object> headers = context.getHeaders();
        headers.add(HmacHeaderValue.X_SIGNATURE.headerName(), signature);
        context.proceed();
    } catch (IllegalArgumentException | ParseException | InvalidKeyException | NoSuchAlgorithmException ex) {
        LOGGER.error(ex.getMessage());
    } catch (UnsupportedEncodingException ex) {
        LOGGER.error(ex.getMessage());
    } catch (IOException ex) {
        LOGGER.error(ex.getMessage());
    }
}

此处 doSomeSuffWithPayload(payload) 方法不起作用,因为有效负载始终为空。

我认为一个技巧可以做到这一点,所以我将 context.proceed() 调用切换到任何其他位置:

public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException {
    try {
        context.proceed();
        final ClientOutputStream stream = (ClientOutputStream) requestContext.getProperty(HTTPCLIENT_ENTITY_STREAM);
        String payload = stream.getString(Charset.forName("UTF-8")); // returns the right string representation
        String signature = doSomeSuffWithPayload(payload);

        MultivaluedMap<String, Object> headers = context.getHeaders();
        headers.add(HmacHeaderValue.X_SIGNATURE.headerName(), signature); // doesn't add the header
    } catch (IllegalArgumentException | ParseException | InvalidKeyException | NoSuchAlgorithmException ex) {
        LOGGER.error(ex.getMessage());
    } catch (UnsupportedEncodingException ex) {
        LOGGER.error(ex.getMessage());
    } catch (IOException ex) {
        LOGGER.error(ex.getMessage());
    }
}

在这种情况下,实体的字符串表示形式就可以了。但是将 header 添加到请求中不起作用。

所以 atm 我可以将(错误的)签名添加到 header 和始终为空的实体中,或者将正确的签名添加到正确的实体中,但不会添加 header 。

我的问题是:有人知道如何使用 WriterInterceptor 获取实体的字符串表示形式吗?

伊迪丝说:

我们使用的是 2.25.1 版本的 Jersey 客户端。 2.27也没有解决问题。

最佳答案

在深入搜索 API 后,我发现该实体确实是在 MessageBodyWriter 中的 WriterInterceptor 之后写入的。除此之外, header 也会在此过程中添加到 MessageBodyWriter 中。这就是为什么上述两种方法都不起作用的原因。

我的解决方案 atm 是获取正确的 MessageBodyWriter 并让它序列化实体,就像在 WriterInterceptor 之后执行的 MessageBodyWriter 中一样。在这种情况下,不再需要 WriterInterceptor,实现 ClientRequestFilter 就可以了。

import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.ext.Providers;

@Context
private Providers providers;

private String getPayloadFromRequest(ClientRequestContext requestContext) throws IOException {
    Object object = requestContext.getEntity();
    if (object != null) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try {
            // buffer into which myBean will be serialized
            Class<Object> type = (Class<Object>) requestContext
                    .getEntityClass();
            GenericType<Object> genericType = new GenericType<Object>(type) {
            };

            // get most appropriate MBW
            final MessageBodyWriter<Object> messageBodyWriter = providers
                    .getMessageBodyWriter(type, type, new Annotation[]{},
                            MediaType.APPLICATION_JSON_TYPE);

            try {
                // use the MBW to serialize myBean into baos
                messageBodyWriter.writeTo(object, object.getClass(),
                        genericType.getType(), new Annotation[]{},
                        MediaType.APPLICATION_JSON_TYPE,
                        new MultivaluedHashMap<String, Object>(), baos);
            } catch (IOException e) {
                throw new RuntimeException(
                        "Error while serializing MyBean.", e);
            }

            return baos.toString();
        } finally {
            baos.close();
        }

    } else {
        return "";
    }
}

该代码不是我的,但不幸的是我丢失了源代码。

关于java - 如何在 Jersey 客户端中读取有效负载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53558848/

相关文章:

java - 如何在java中发出HTTP post请求登录时获取cookie并发布它

java - 带有 @Min 的可空整数 QueryParam 上的 ConstraintViolationException

eclipse - 在 Eclipse 中部署 REST Web 服务的问题

java - 使用 Jersey RxJava 客户端未找到类 rx.Observable 的序列化器

java - Jersey 客户端收到错误的响应

java - 使用 REST API 在 azure 存储中创建目录

java - OffsetDateTime解析

java - Eclipse:启动静态资源时出错 java.lang.IllegalArgumentException

tomcat - 无法通过 Jersey 解决 404 错误

java - 使用 FormDataMultiPart 发送实体和文件