0

我正在使用 Jersey (ver 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 是否从文件中修改流中的数据?出了什么问题?

更新:

如果我从浏览器点击相同的 url,它会下载文件但下载的文件不可见。所以这个问题似乎与服务器有关。

4

3 回答 3

1

对服务器采取不同的方法。如泽西手册中所述或如下所示:

@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 带宽。

于 2012-12-31T19:23:40.207 回答
1

我会尝试返回输入流而不是 File 对象。我认为媒体类型可能被弄乱了,或者默认文件处理弄乱了输出。所以使用也许:

Response.ok(new FileInputStream(imageFile), "image/png") .header("Content-Disposition","attachment; filename=Img" + userId + ".png") .build();

于 2013-01-01T08:57:47.757 回答
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();,这解决了问题。

于 2013-01-01T11:33:42.140 回答