问题
I am trying to set the Content-MD5 header on a request created with the Jersey Client API. I have created ClientFilter which implements another adapter (similar to how the GZipFilter works). Like this:
public class ContentMD5Filter extends ClientFilter {
private static final class ContentMD5Adapter extends AbstractClientRequestAdapter {
ContentMD5Adapter(final ClientRequestAdapter cra) {
super(cra);
}
@Override
public OutputStream adapt(final ClientRequest request, final OutputStream out) throws IOException {
try {
MessageDigest instance = MessageDigest.getInstance("MD5");
request.getHeaders().add("Content-MD5", instance);
return new DigestOutputStream(out, instance);
} catch (NoSuchAlgorithmException e) {
throw new WebApplicationException();
}
}
}
@Override
public ClientResponse handle(final ClientRequest cr) throws ClientHandlerException {
cr.setAdapter(new ContentMD5Adapter(cr.getAdapter()));
return getNext().handle(cr);
}
}
This doesn't work, as the digest are read to early (ie. before the whole content is written.
Any ideas on how to do this? As well as setting the header, I need to access it in another filter afterwards (to implement a security mechanism)
回答1:
I found the solution. It's a quite complex way to do it, since I have to temporarily store the outputstream, but I guess you can figure it out if you need this yourself :)
The code for the filter:
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import com.sun.jersey.api.client.AbstractClientRequestAdapter;
import com.sun.jersey.api.client.ClientHandlerException;
import com.sun.jersey.api.client.ClientRequest;
import com.sun.jersey.api.client.ClientRequestAdapter;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.filter.ClientFilter;
public class ContentMD5Filter extends ClientFilter {
@Override
public ClientResponse handle(final ClientRequest cr) throws ClientHandlerException {
cr.setAdapter(new ContentMD5Adapter(cr.getAdapter()));
return getNext().handle(cr);
}
private static final class ContentMD5Adapter extends AbstractClientRequestAdapter {
ContentMD5Adapter(final ClientRequestAdapter cra) {
super(cra);
}
@Override
public OutputStream adapt(final ClientRequest request, final OutputStream out) throws IOException {
return new ContentMD5OutputStream(request, getAdapter().adapt(request, out));
}
}
private static final class ContentMD5OutputStream extends OutputStream {
private final ByteArrayOutputStream byteArrayOutputStream;
private final OutputStream jerseyStream;
private final ClientRequest request;
public ContentMD5OutputStream(final ClientRequest request, final OutputStream jerseyStream) {
this.jerseyStream = jerseyStream;
this.request = request;
byteArrayOutputStream = new ByteArrayOutputStream();
}
@Override
public void write(final int b) throws IOException {
byteArrayOutputStream.write(b);
}
@Override
public void close() throws IOException {
byteArrayOutputStream.close();
byte[] byteArray = byteArrayOutputStream.toByteArray();
setContentMD5Header(byteArray);
IOUtils.write(byteArray, jerseyStream);
jerseyStream.close();
}
private void setContentMD5Header(final byte[] data) {
try {
MessageDigest instance = MessageDigest.getInstance("MD5");
String contentMD5 = new String(Base64.encodeBase64(instance.digest(data)));
request.getHeaders().add("Content-MD5", contentMD5);
} catch (NoSuchAlgorithmException e) {
// Errorhandling. Should not happen though!
}
}
}
}
To use this filter:
Client client = Client.create();
webResource = client.resource("http://localhost:8080/pathToYourResource");
contentMD5filter = new ContentMD5Filter();
webResource.addFilter(contentMD5filter);
来源:https://stackoverflow.com/questions/6279102/content-md5-in-jerseys-client-api