我在这里有一个小问题。触发请求时,我想用HMAC对整个消息进行签名,然后将结果签名添加到标题中。
所以我实现了
javax.ws.rs.ext.WriterInterceptorContext
在
public void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException
方法我无法访问实体的字符串表示形式。它总是返回一个空的字符串。原因似乎是在WriterInterceptor之后执行的MessageBodyWriter。
基本上,我遇到以下两种情况:
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());
}
}
在这种情况下,实体的字符串表示形式可以。但是将标头添加到请求中是行不通的。
所以atm我可以将(错误的)签名添加到标头中,并且将实体始终为空,或者将正确的签名与正确的实体添加在一起,但不添加标头。
我的问题是:是否有人知道使用WriterInterceptor获取实体的字符串表示形式的方法?
EDITH说:
我们正在使用球衣客户端的2.25.1版本。 2.27也不能解决问题。
答案 0 :(得分:0)
深入研究API之后,我发现该实体确实在MessageBodyWriter中的WriterInterceptor之后写入。此外,还可以在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 "";
}
}
代码不是我的,但不幸的是我丢失了源代码。