我正在使用Jersey(版本1.9.1)为png图像实现RESTful Web服务。我在客户端使用Apache HttpClient(版本4x)。客户端的代码调用HttpGet来下载图像。成功下载后,它会将InputStream从HttpEntity保存到磁盘。现在问题是结果文件和服务器上的文件是不同的。客户端代码生成的输出图像文件不是可渲染的。
@GET
@Path("/public/profile/{userId}")
@Produces({ "image/png" })
public Response getImage(@PathParam(value = "userId") String userId) {
Response res = null;
// ImageManagement.gerProfilePicture(userId) returns me profile picture
// of the provided userId in PathParam
File imageFile = ImageManagement.getProfilePicture(userId);
if (imageFile == null) {
res = Response.status(Status.NOT_FOUND).build();
} else {
res = Response
.ok(imageFile, "image/png")
.header("Content-Disposition",
"attachment; filename=Img" + userId + ".png")
.build();
}
return res;
}
我的客户端代码调用上面的资源方法
private File downloadProfilePicture(String userId) throws IOException{
// URIHelper is a utility class, this give me uri for image resource
URI imageUri = URIHelper.buildURIForProfile(userId);
HttpGet httpGet = new HttpGet(imageUri);
HttpResponse httpResponse = httpClient.execute(httpGet);
int statusCode = httpResponse.getStatusLine().getStatusCode();
File imageFile = null;
if (statusCode == HttpURLConnection.HTTP_OK) {
HttpEntity httpEntity = httpResponse.getEntity();
Header[] headers = httpResponse.getHeaders("Content-Disposition");
imageFile = new File(OUTPUT_DIR, headers[0].getElements()[0]
.getParameterByName("filename").getValue());
FileOutputStream foutStream = new FileOutputStream(imageFile);
httpEntity.writeTo(foutStream);
foutStream.close();
}
return imageFile;
}
现在问题是服务器上存在文件,下载的文件不同。
以下是服务器上存在的文件转储。
下面是下载文件的转储。
你可以看到,一些字节正在改变。 Jersey服务器api是否修改了文件流中的数据?出了什么问题?
更新
如果我从浏览器点击同一个网址,则会下载该文件,但下载的文件无法查看。所以问题似乎与服务器有关。
答案 0 :(得分:1)
对服务器采取不同的方法。无论是documented in the Jersey manual还是像这样:
@GET
@Path("/public/profile/{userId}")
@Produces("image/png")
public Response getFullImage(...) {
Path path = Paths.get("path/to/file");
byte[] imageData = Files.readAllBytes(path);
// uncomment line below to send non-streamed
// return Response.ok(imageData).build();
// uncomment line below to send streamed
// return Response.ok(new ByteArrayInputStream(imageData)).build();
}
旁注:我认为在REST服务中返回图像数据并不是一个好主意。它占用了服务器的内存和I / O带宽。
答案 1 :(得分:1)
我会尝试返回输入流而不是File对象。我认为媒体类型可能会搞乱,或者默认文件处理正在弄乱输出。所以使用may:
Response.ok(new FileInputStream(imageFile),“image / png”) .header(“Content-Disposition”,“attachment; filename = Img”+ userId +“。png”) .build();
答案 2 :(得分:0)
我发现这是我的错。我正在修改过滤器代码中的响应数据(通过更改它的编码)。此过滤器用于设置内容长度标头并处理“eTag”。这个想法来自这里:http://www.infoq.com/articles/etags
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest servletRequest = (HttpServletRequest) request;
HttpServletResponse servletResponse = (HttpServletResponse) response;
HttpResponseCatcher wrapper = new HttpResponseCatcher(
(HttpServletResponse) response);
chain.doFilter(request, wrapper);
final byte[] responseBytes = wrapper.getByteArray();
String digest = getMd5Digest(responseBytes);
String etag = '"' + digest + '"';
// always store the ETag in the header
servletResponse.setHeader("ETag", etag);
String previousEtag = servletRequest.getHeader("If-None-Match");
// compare previous token with current one
if (previousEtag != null && previousEtag.equals(etag)) {
servletResponse.sendError(HttpServletResponse.SC_NOT_MODIFIED);
// use the same date we sent when we created the ETag the first time
// through
servletResponse.setHeader("Last-Modified",
servletRequest.getHeader("If-Modified-Since"));
} else {
// first time through - set last modified time to now
Calendar cal = Calendar.getInstance();
cal.set(Calendar.MILLISECOND, 0);
Date lastModified = cal.getTime();
servletResponse.setDateHeader("Last-Modified",
lastModified.getTime());
servletResponse.setContentLength(responseBytes.length);
ServletOutputStream sos = servletResponse.getOutputStream();
sos.write(responseBytes);
sos.flush();
sos.close();
}
}
我有一个扩展HttpServletResponseWrapper的HttpResponseCacher类。
public class HttpResponseCatcher extends HttpServletResponseWrapper {
private ByteArrayOutputStream buffer;
public HttpResponseCatcher(HttpServletResponse res) {
super(res);
this.buffer = new ByteArrayOutputStream();
}
//There is some more code in the class, but that is not relevant to the problem...
public byte[] getByteArray() {
//The problem is here... this.buffer.toString().getBytes() changes to encoding of the data
return this.buffer.toString().getBytes();
}
}
我将byte[] getByteArray()
中的代码从return this.buffer.toString().getBytes();
更改为return this.buffer.toByteArray();
,这解决了问题。