2012-06-24 11 views
12

Khi đặt các tệp lớn làm InputStream bằng ứng dụng Jersey, có vẻ như toàn bộ nội dung của tệp đang được lưu vào bộ nhớ trước khi được gửi tới máy chủ. Điều này gây ra sự cố với các tệp lớn khi JVM hết dung lượng lưu trữ. Làm cách nào để ngăn chặn hành vi này trong ứng dụng khách của Jersey? Các phương thức tài nguyên JAX-RS ở phía máy chủ dường như không có vấn đề này khi gửi dữ liệu.Ngăn chặn máy khách Jersey gây ra lỗi outofmemory khi đăng các tệp lớn

Ví dụ:

WebResource dataUploadResource = buildDataUploadResource(); 
dataUploadResource.type(getMimeType()).put(getLargeInputStream()); 

Trả lời

13

Để ngăn chặn hành vi này, bạn cần cấu hình máy khách Jersey sử dụng chunked mã hóa 1 cho yêu cầu. Điều này loại bỏ sự cần thiết phải thiết lập một tiêu đề Content-Length và sẽ truyền từ InputStream được cung cấp mà không đệm toàn bộ nội dung trong bộ nhớ.

Theo mặc định, Jersey sử dụng lớp HttpURLConection của JDK để xử lý các yêu cầu và phản hồi HTTP. Thật không may này có một số lỗi liên quan đến chuyển mã hóa chunked. May mắn thay, Jersey có các điểm mở rộng để cho phép các ứng dụng khách HTTP khác nhau được sử dụng. Một triển khai như vậy dựa trên Ứng dụng khách Apache Apache 2.

Hai triển khai của trình xử lý máy khách apache htpp tồn tại, một phiên bản hỗ trợ cuối phiên bản 3.x, phiên bản còn lại sử dụng phiên bản 4.x mới hơn. Đối với dự án của chúng tôi, chúng tôi đã sử dụng triển khai dựa trên phiên bản cũ hơn (3.1). Thư viện có sẵn trong Maven Central dưới tiểu nhóm 'contribs'.

<dependency> 
    <groupId>com.sun.jersey.contribs</groupId> 
    <artifactId>jersey-apache-client</artifactId> 
    <version>1.14</version> 
</dependency> 

Tiếp theo, bạn phải khởi client Jersey của bạn để sử dụng việc thực hiện mới:

Client jerseyClient = ApacheHttpClient.create(getClientConfig()); 

Để kích hoạt mã hóa chunked, bạn sẽ phải thiết lập kích thước mã hóa chunked vào cấu hình máy khách như nó không được kích hoạt theo mặc định:

private ClientConfig getClientConfig() { 
    ClientConfig config = new DefaultClientConfig(); 

    config.getProperties().put(
      DefaultApacheHttpClientConfig.PROPERTY_CHUNKED_ENCODING_SIZE, 0); 
    return config; 
} 

Miễn là thuộc tính này không phải là null, mã hóa chunked sẽ được sử dụng. Trong thực tế, phiên bản 1.14 bỏ qua kích thước mã hóa như chỉ định kích thước không được hỗ trợ bởi thư viện commons-httpclient cơ bản apache.

+1

Thật không may, điều này dường như không hoạt động đáng tin cậy - đó là lý do tại sao chúng tôi đã mã hóa chunked nhận xét theo mặc định trong mã Jersey. Dường như có một lỗi khó chịu trong HttpURLConnection khiến một số yêu cầu thất bại một cách kỳ lạ và bán ngẫu nhiên (tập con của các thử nghiệm của chúng tôi thất bại, nếu chúng ta chạy lại các kiểm tra không thành công, một tập con nhỏ hơn sẽ không thành công, nếu chúng ta chạy lại chỉ là tập hợp con đó, ngay cả một tập hợp con nhỏ hơn không thành công và cuối cùng là tất cả đều vượt qua). Vì vậy, tôi khuyên bạn nên sử dụng một trình kết nối khách hàng mạnh mẽ hơn cho bất kỳ công việc nghiêm túc nào. –

+1

Cảm ơn phản hồi của bạn. Tôi đã cập nhật câu trả lời để hiển thị cách cấu hình máy khách sử dụng mã hóa chunked bằng cách sử dụng trình kết nối máy khách Apache Http. – Eric