如何使用使用 PHP 的 Java HttpClient 库上传文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1067655/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to upload a file using Java HttpClient library working with PHP
提问by Piotr Kochański
I want to write Java application that will upload a file to the Apache server with PHP. The Java code uses Jakarta HttpClient library version 4.0 beta2:
我想编写将使用 PHP 将文件上传到 Apache 服务器的 Java 应用程序。Java 代码使用 Jakarta HttpClient 库版本 4.0 beta2:
import java.io.File;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.FileEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.util.EntityUtils;
public class PostFile {
public static void main(String[] args) throws Exception {
HttpClient httpclient = new DefaultHttpClient();
httpclient.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
HttpPost httppost = new HttpPost("http://localhost:9002/upload.php");
File file = new File("c:/TRASH/zaba_1.jpg");
FileEntity reqEntity = new FileEntity(file, "binary/octet-stream");
httppost.setEntity(reqEntity);
reqEntity.setContentType("binary/octet-stream");
System.out.println("executing request " + httppost.getRequestLine());
HttpResponse response = httpclient.execute(httppost);
HttpEntity resEntity = response.getEntity();
System.out.println(response.getStatusLine());
if (resEntity != null) {
System.out.println(EntityUtils.toString(resEntity));
}
if (resEntity != null) {
resEntity.consumeContent();
}
httpclient.getConnectionManager().shutdown();
}
}
The PHP file upload.php
is very simple:
PHP文件upload.php
非常简单:
<?php
if (is_uploaded_file($_FILES['userfile']['tmp_name'])) {
echo "File ". $_FILES['userfile']['name'] ." uploaded successfully.\n";
move_uploaded_file ($_FILES['userfile'] ['tmp_name'], $_FILES['userfile'] ['name']);
} else {
echo "Possible file upload attack: ";
echo "filename '". $_FILES['userfile']['tmp_name'] . "'.";
print_r($_FILES);
}
?>
Reading the response I get the following result:
阅读响应我得到以下结果:
executing request POST http://localhost:9002/upload.php HTTP/1.1
HTTP/1.1 200 OK Possible file upload attack: filename ''. Array ( )
So the request was successful, I was able to communicate with server, however PHP didn't notice the file - the method is_uploaded_file
returned false
and $_FILES
variable is empty. I have no idea why this might happend. I have tracked HTTP response and request and they look ok:
request is:
所以请求成功,我能够与服务器通信,但是 PHP 没有注意到该文件 -is_uploaded_file
返回的方法false
和$_FILES
变量为空。我不知道为什么会发生这种情况。我已经跟踪了 HTTP 响应和请求,它们看起来没问题:
请求是:
POST /upload.php HTTP/1.1 Content-Length: 13091 Content-Type: binary/octet-stream Host: localhost:9002 Connection: Keep-Alive User-Agent: Apache-HttpClient/4.0-beta2 (java 1.5) Expect: 100-Continue ˙?˙?..... the rest of the binary file...
and response:
和回应:
HTTP/1.1 100 Continue HTTP/1.1 200 OK Date: Wed, 01 Jul 2009 06:51:57 GMT Server: Apache/2.2.8 (Win32) DAV/2 mod_ssl/2.2.8 OpenSSL/0.9.8g mod_autoindex_color PHP/5.2.5 mod_jk/1.2.26 X-Powered-By: PHP/5.2.5 Content-Length: 51 Keep-Alive: timeout=5, max=100 Connection: Keep-Alive Content-Type: text/html Possible file upload attack: filename ''.Array ( )
I was testing this both on the local windows xp with xampp and remote Linux server. I have also tried to use previous version of HttpClient - version 3.1 - and the result was even more unclear, is_uploaded_file
returned false
, however $_FILES
array was filled with proper data.
我正在使用 xampp 和远程 Linux 服务器在本地 windows xp 上测试这个。我还尝试使用以前版本的 HttpClient - 3.1 版 - 结果更加不清楚,is_uploaded_file
返回false
,但是$_FILES
数组填充了正确的数据。
采纳答案by Piotr Kochański
Ok, the Java code I used was wrong, here comes the right Java class:
好吧,我使用的Java代码是错误的,正确的Java类来了:
import java.io.File;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.ContentBody;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.util.EntityUtils;
public class PostFile {
public static void main(String[] args) throws Exception {
HttpClient httpclient = new DefaultHttpClient();
httpclient.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
HttpPost httppost = new HttpPost("http://localhost:9001/upload.php");
File file = new File("c:/TRASH/zaba_1.jpg");
MultipartEntity mpEntity = new MultipartEntity();
ContentBody cbFile = new FileBody(file, "image/jpeg");
mpEntity.addPart("userfile", cbFile);
httppost.setEntity(mpEntity);
System.out.println("executing request " + httppost.getRequestLine());
HttpResponse response = httpclient.execute(httppost);
HttpEntity resEntity = response.getEntity();
System.out.println(response.getStatusLine());
if (resEntity != null) {
System.out.println(EntityUtils.toString(resEntity));
}
if (resEntity != null) {
resEntity.consumeContent();
}
httpclient.getConnectionManager().shutdown();
}
}
note using MultipartEntity.
注意使用 MultipartEntity。
回答by Fenton
If you are testing this on your local WAMP you might need to set up the temporary folder for file uploads. You can do this in your PHP.ini file:
如果您在本地 WAMP 上对此进行测试,您可能需要为文件上传设置临时文件夹。您可以在 PHP.ini 文件中执行此操作:
upload_tmp_dir = "c:\mypath\mytempfolder\"
You will need to grant permissions on the folder to allow the upload to take place - the permission you need to grant vary based on your operating system.
您需要授予文件夹权限以允许上传 - 您需要授予的权限因操作系统而异。
回答by kgiannakakis
The correct way will be to use multipart POST method. See herefor example code for the client.
正确的方法是使用多部分 POST 方法。有关客户端的示例代码,请参见此处。
For PHP there are many tutorials available. This is the firstI've found. I recommend that you test the PHP code first using an html client and then try the java client.
对于 PHP,有许多可用的教程。这是我发现的第一个。我建议您先使用 html 客户端测试 PHP 代码,然后再尝试使用 java 客户端。
回答by fervisa
For those having a hard time implementing the accepted answer (which requires org.apache.http.entity.mime.MultipartEntity) you may be using org.apache.httpcomponents 4.2.* In this case, you have to explicitly installhttpmimedependency, in my case:
对于那些难以实现接受的答案(需要 org.apache.http.entity.mime.MultipartEntity)的人,您可能正在使用 org.apache.httpcomponents 4.2.* 在这种情况下,您必须明确安装httpmime依赖项,在我的情况:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.2.5</version>
</dependency>
回答by gaojun1000
I ran into the same problem and found out that the file name is required for httpclient 4.x to be working with PHP backend. It was not the case for httpclient 3.x.
我遇到了同样的问题,发现 httpclient 4.x 需要文件名才能与 PHP 后端一起使用。httpclient 3.x 并非如此。
So my solution is to add a name parameter in the FileBody constructor. ContentBody cbFile = new FileBody(file, "image/jpeg", "FILE_NAME");
所以我的解决方案是在 FileBody 构造函数中添加一个 name 参数。ContentBody cbFile = new FileBody(file, "image/jpeg", "FILE_NAME");
Hope it helps.
希望能帮助到你。
回答by Brent Robinson
An update for those trying to use MultipartEntity
...
对于那些试图使用的人的更新MultipartEntity
......
org.apache.http.entity.mime.MultipartEntity
is deprecated in 4.3.1.
org.apache.http.entity.mime.MultipartEntity
在 4.3.1 中已弃用。
You can use MultipartEntityBuilder
to create the HttpEntity
object.
您可以使用MultipartEntityBuilder
来创建HttpEntity
对象。
File file = new File();
HttpEntity httpEntity = MultipartEntityBuilder.create()
.addBinaryBody("file", file, ContentType.create("image/jpeg"), file.getName())
.build();
For Maven users the class is available in the following dependency (almost the same as fervisa's answer, just with a later version).
对于 Maven 用户,该类可在以下依赖项中使用(与 fervisa 的答案几乎相同,只是具有更高版本)。
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>4.3.1</version>
</dependency>
回答by Krystian
There is my working solution for sending image with post, using apache http libraries (very important here is boundary add It won't work without it in my connection):
有我使用 apache http 库发送图像的工作解决方案(这里非常重要的是边界添加它在我的连接中没有它就无法工作):
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
byte[] imageBytes = baos.toByteArray();
HttpClient httpclient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(StaticData.AMBAJE_SERVER_URL + StaticData.AMBAJE_ADD_AMBAJ_TO_GROUP);
String boundary = "-------------" + System.currentTimeMillis();
httpPost.setHeader("Content-type", "multipart/form-data; boundary="+boundary);
ByteArrayBody bab = new ByteArrayBody(imageBytes, "pic.png");
StringBody sbOwner = new StringBody(StaticData.loggedUserId, ContentType.TEXT_PLAIN);
StringBody sbGroup = new StringBody("group", ContentType.TEXT_PLAIN);
HttpEntity entity = MultipartEntityBuilder.create()
.setMode(HttpMultipartMode.BROWSER_COMPATIBLE)
.setBoundary(boundary)
.addPart("group", sbGroup)
.addPart("owner", sbOwner)
.addPart("image", bab)
.build();
httpPost.setEntity(entity);
try {
HttpResponse response = httpclient.execute(httpPost);
...then reading response
回答by Krystian
Aah you just need to add a name parameter in the
啊,你只需要在
FileBody constructor. ContentBody cbFile = new FileBody(file, "image/jpeg", "FILE_NAME");
Hope it helps.
希望能帮助到你。
回答by rado
A newer version example is here.
Below is a copy of the original code:
以下是原始代码的副本:
/*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
*/
package org.apache.http.examples.entity.mime;
import java.io.File;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
/**
* Example how to use multipart/form encoded POST request.
*/
public class ClientMultipartFormPost {
public static void main(String[] args) throws Exception {
if (args.length != 1) {
System.out.println("File path not given");
System.exit(1);
}
CloseableHttpClient httpclient = HttpClients.createDefault();
try {
HttpPost httppost = new HttpPost("http://localhost:8080" +
"/servlets-examples/servlet/RequestInfoExample");
FileBody bin = new FileBody(new File(args[0]));
StringBody comment = new StringBody("A binary file of some kind", ContentType.TEXT_PLAIN);
HttpEntity reqEntity = MultipartEntityBuilder.create()
.addPart("bin", bin)
.addPart("comment", comment)
.build();
httppost.setEntity(reqEntity);
System.out.println("executing request " + httppost.getRequestLine());
CloseableHttpResponse response = httpclient.execute(httppost);
try {
System.out.println("----------------------------------------");
System.out.println(response.getStatusLine());
HttpEntity resEntity = response.getEntity();
if (resEntity != null) {
System.out.println("Response content length: " + resEntity.getContentLength());
}
EntityUtils.consume(resEntity);
} finally {
response.close();
}
} finally {
httpclient.close();
}
}
}
回答by Dev
I knew I am late to the party but below is the correct way to deal with this, the key is to use InputStreamBody
in place of FileBody
to upload multi-part file.
我知道我迟到了,但下面是处理这个问题的正确方法,关键是使用InputStreamBody
代替FileBody
上传多部分文件。
try {
HttpClient httpclient = new DefaultHttpClient();
HttpPost postRequest = new HttpPost("https://someserver.com/api/path/");
postRequest.addHeader("Authorization",authHeader);
//don't set the content type here
//postRequest.addHeader("Content-Type","multipart/form-data");
MultipartEntity reqEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
File file = new File(filePath);
FileInputStream fileInputStream = new FileInputStream(file);
reqEntity.addPart("parm-name", new InputStreamBody(fileInputStream,"image/jpeg","file_name.jpg"));
postRequest.setEntity(reqEntity);
HttpResponse response = httpclient.execute(postRequest);
}catch(Exception e) {
Log.e("URISyntaxException", e.toString());
}