0

png 画像用の RESTful Web サービスを実装するために Jersey (ver 1.9.1) を使用しています。クライアント側で Apache HttpClient (ver. 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 に答える