type tipo subir personalizar name estilos estilo darle dar como boton archivos file-upload jersey large-files

file-upload - subir - personalizar input tipo file



Cómo evitar OutOfMemoryError al cargar un archivo grande con el cliente de Jersey (6)

Estoy utilizando el cliente de Jersey para la solicitud basada en http. Funciona bien si el archivo es pequeño pero tiene un error cuando publico un archivo con un tamaño de 700M:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at java.util.Arrays.copyOf(Arrays.java:2786) at java.io.ByteArrayOutputStream.write(ByteArrayOutputStream.java:94) at sun.net.www.http.PosterOutputStream.write(PosterOutputStream.java:61) at com.sun.jersey.api.client.CommittingOutputStream.write(CommittingOutputStream.java:90) at com.sun.jersey.core.util.ReaderWriter.writeTo(ReaderWriter.java:115) at com.sun.jersey.core.provider.AbstractMessageReaderWriterProvider.writeTo(AbstractMessageReaderWriterProvider.java:76) at com.sun.jersey.core.impl.provider.entity.FileProvider.writeTo(FileProvider.java:103) at com.sun.jersey.core.impl.provider.entity.FileProvider.writeTo(FileProvider.java:64) at com.sun.jersey.multipart.impl.MultiPartWriter.writeTo(MultiPartWriter.java:224) at com.sun.jersey.multipart.impl.MultiPartWriter.writeTo(MultiPartWriter.java:71) at com.sun.jersey.api.client.RequestWriter.writeRequestEntity(RequestWriter.java:300) at com.sun.jersey.client.urlconnection.URLConnectionClientHandler._invoke(URLConnectionClientHandler.java:204) at com.sun.jersey.client.urlconnection.URLConnectionClientHandler.handle(URLConnectionClientHandler.java:147) at com.sun.jersey.api.client.Client.handle(Client.java:648) at com.sun.jersey.api.client.WebResource.handle(WebResource.java:680) at com.sun.jersey.api.client.WebResource.access$200(WebResource.java:74) at com.sun.jersey.api.client.WebResource$Builder.post(WebResource.java:568) at TestHttpRequest.main(TestHttpRequest.java:42)

Aquí está mi código:

ClientConfig cc = new DefaultClientConfig(); Client client = Client.create(cc); WebResource resource = client.resource("http://localhost:8080/JerseyWithServletTest/helloworld"); FormDataMultiPart form = new FormDataMultiPart(); File file = new File("E:/CN_WXPPSP3_v312.ISO"); form.field("username", "ljy"); form.field("password", "password"); form.field("filename", file.getName()); form.bodyPart(new FileDataBodyPart("file", file, MediaType.MULTIPART_FORM_DATA_TYPE)); ClientResponse response = resource.type(MediaType.MULTIPART_FORM_DATA).post(ClientResponse.class, form);


A continuación se muestra el código para cargar un archivo (potencialmente grande) con codificación de transferencia fragmentada (es decir, secuencias) utilizando Jersey 2.11.

Maven

<properties> <jersey.version>2.11</jersey.version> </properties> <dependencies> <dependency> <groupId>org.glassfish.jersey.core</groupId> <artifactId>jersey-client</artifactId> <version>${jersey.version}</version> </dependency> <dependency> <groupId>org.glassfish.jersey.media</groupId> <artifactId>jersey-media-multipart</artifactId> <version>${jersey.version}</version> </dependency> <dependencies>

Java:

Client client = ClientBuilder.newClient(clientConfig); client.property(ClientProperties.REQUEST_ENTITY_PROCESSING, "CHUNKED"); WebTarget target = client.target(SERVICE_URI); InputStream fileInStream = new FileInputStream(inFile); String contentDisposition = "attachment; filename=/"" + inFile.getName() + "/""; System.out.println("sending: " + inFile.length() + " bytes..."); Response response = target .request(MediaType.APPLICATION_OCTET_STREAM_TYPE) .header("Content-Disposition", contentDisposition) .header("Content-Length", (int) inFile.length()) .put(Entity.entity(fileInStream, MediaType.APPLICATION_OCTET_STREAM_TYPE)); System.out.println("Response status: " + response.getStatus());


En mi caso (Jersey 2.23.2) la solución de rschmidt13 dio esta advertencia:

WARNING: Attempt to send restricted header(s) while the [sun.net.http.allowRestrictedHeaders] system property not set. Header(s) will possibly be ignored.

Esto se puede resolver agregando la siguiente línea:

System.setProperty("sun.net.http.allowRestrictedHeaders", "true");

Sin embargo, creo que se puede obtener una solución más limpia utilizando la interfaz StreamingOutput . Publico un ejemplo completo con la esperanza de que pueda ser útil.

Cliente (carga de archivos)

WebTarget target = ClientBuilder.newBuilder().build() .property(ClientProperties.CHUNKED_ENCODING_SIZE, 1024) .property(ClientProperties.REQUEST_ENTITY_PROCESSING, "CHUNKED") .target("<your-url>"); StreamingOutput out = new StreamingOutput() { @Override public void write(OutputStream output) throws IOException, WebApplicationException { try (FileInputStream is = new FileInputStream(file)) { int available; while ((available = is.available()) > 0) { // or use a buffer output.write(is.read()); } } } }; Response response = target.request().post(Entity.text(out));

Servidor

@Path("resourcename") public class MyResource { @Context HttpServletRequest request; @POST @Path("thepath") public Response upload() throws IOException, ServletException { try (InputStream is = request.getInputStream()) { // ... } } }


Para que su código no dependa del tamaño del archivo cargado, necesita:

  1. Usar arroyos
  2. Definir el tamaño de mandril del cliente de jersey. Por ejemplo: client.setChunkedEncodingSize(1024);

Servidor :

@POST @Path("/upload/{attachmentName}") @Consumes(MediaType.APPLICATION_OCTET_STREAM) public void uploadAttachment(@PathParam("attachmentName") String attachmentName, InputStream attachmentInputStream) { // do something with the input stream }

Cliente :

... client.setChunkedEncodingSize(1024); WebResource rootResource = client.resource("your-server-base-url"); File file = new File("your-file-path"); InputStream fileInStream = new FileInputStream(file); String contentDisposition = "attachment; filename=/"" + file.getName() + "/""; ClientResponse response = rootResource.path("attachment").path("upload").path("your-file-name") .type(MediaType.APPLICATION_OCTET_STREAM).header("Content-Disposition", contentDisposition) .post(ClientResponse.class, fileInStream);


Podrías usar streams. Prueba algo como esto en el cliente:

InputStream fileInStream = new FileInputStream(fileName); String sContentDisposition = "attachment; filename=/"" + fileName.getName()+"/""; WebResource fileResource = a_client.resource(a_sUrl); ClientResponse response = fileResource.type(MediaType.APPLICATION_OCTET_STREAM) .header("Content-Disposition", sContentDisposition) .post(ClientResponse.class, fileInStream);

con recursos como este en el servidor:

@PUT @Consumes("application/octet-stream") public Response putFile(@Context HttpServletRequest a_request, @PathParam("fileId") long a_fileId, InputStream a_fileInputStream) throws Throwable { // Do something with a_fileInputStream // etc


Si es posible, ¿puede dividir el archivo que envía en partes más pequeñas? Esto reducirá el uso de la memoria, pero debe cambiar el código en ambos lados del código de carga / descarga.

Si no puede, entonces su espacio de almacenamiento es demasiado bajo, intente aumentarlo con este parámetro JVM. En su servidor de aplicaciones, agregue / cambie las opciones de Xmx JVM. Por ejemplo

-Xmx1024m

configurar el espacio de almacenamiento máximo a 1 Gb


@Consumes("multipart/form-data") @Produces(MediaType.TEXT_PLAIN + ";charset=utf-8") public String upload(MultipartFormDataInput input, @QueryParam("videoId") String videoId, @Context HttpServletRequest a_request) { String fileName = ""; for (InputPart inputPart : input.getParts()) { try { MultivaluedMap<String, String> header = inputPart.getHeaders(); fileName = getFileName(header); // convert the uploaded file to inputstream InputStream inputStream = inputPart.getBody(InputStream.class, null); // write the inputStream to a FileOutputStream OutputStream outputStream = new FileOutputStream(new File("/home/mh/Téléchargements/videoUpload.avi")); int read = 0; byte[] bytes = new byte[1024]; while ((read = inputStream.read(bytes)) != -1) { outputStream.write(bytes, 0, read); } System.out.println("Done!"); } catch (IOException e) { e.printStackTrace(); return "ko"; } }