J'utilise le client Jersey pour les requêtes basées sur http. Cela fonctionne bien si le fichier est petit mais en erreur lorsque je poste un fichier 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)
voici mon code:
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);
Vous pouvez utiliser streams.Essayez quelque chose comme ceci sur le client:
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);
avec une ressource comme celle-ci sur le serveur:
@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
Pour que votre code ne dépende pas de la taille du fichier téléchargé, vous avez besoin des éléments suivants:
client.setChunkedEncodingSize(1024);
Serveur :
@POST
@Path("/upload/{attachmentName}")
@Consumes(MediaType.APPLICATION_OCTET_STREAM)
public void uploadAttachment(@PathParam("attachmentName") String attachmentName, InputStream attachmentInputStream) {
// do something with the input stream
}
Client :
...
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);
Vous trouverez ci-dessous le code permettant de télécharger un fichier (potentiellement volumineux) avec un codage de transfert fragmenté (c'est-à-dire des flux) à l'aide de 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());
Dans mon cas (Jersey 2.23.2) la solution de rschmidt13 a donné cet avertissement:
WARNING: Attempt to send restricted header(s) while the [Sun.net.http.allowRestrictedHeaders] system property not set. Header(s) will possibly be ignored.
Cela peut être résolu en ajoutant la ligne suivante:
System.setProperty("Sun.net.http.allowRestrictedHeaders", "true");
Cependant, je pense qu'une solution plus propre peut être obtenue en utilisant l'interface StreamingOutput
. Je poste un exemple complet dans l'espoir que cela puisse être utile.
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));
@Path("resourcename")
public class MyResource {
@Context
HttpServletRequest request;
@POST
@Path("thepath")
public Response upload() throws IOException, ServletException {
try (InputStream is = request.getInputStream()) {
// ...
}
}
}
Si possible, pouvez-vous diviser le fichier que vous envoyez en parties plus petites? Cela réduira l'utilisation de la mémoire, mais vous devez changer le code des deux côtés du code de téléchargement.
Si vous ne le pouvez pas, votre espace de mémoire est trop faible, essayez de l'augmenter avec ce paramètre de la machine virtuelle Java. Dans votre serveur d'applications, ajoutez/modifiez les options de la JVM Xmx
. Par exemple
-Xmx1024m
définir l'espace de tas maximum à 1Go
@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";
}
}