【问题标题】:How to upload a file using Java HttpClient library working with PHP如何使用与 PHP 一起使用的 Java HttpClient 库上传文件
【发布时间】:2010-11-07 05:57:28
【问题描述】:

我想编写一个 Java 应用程序,该应用程序将使用 PHP 将文件上传到 Apache 服务器。 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();
  }
}

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);
}
?>

阅读回复我得到以下结果:

executing request POST http://localhost:9002/upload.php HTTP/1.1
HTTP/1.1 200 正常 可能的文件上传攻击:文件名''。 大批 ( )

所以请求成功,我能够与服务器通信,但是 PHP 没有注意到该文件 - 方法 is_uploaded_file 返回 false$_FILES 变量为空。我不知道为什么会发生这种情况。我已经跟踪了 HTTP 响应和请求,它们看起来还不错:
请求是:

POST /upload.php HTTP/1.1 内容长度:13091 内容类型:二进制/八位字节流 主机:本地主机:9002 连接:保持活动 用户代理:Apache-HttpClient/4.0-beta2 (java 1.5) 期望:100-继续 ˙Ř˙ŕ.....二进制文件的其余部分...

和回应:

HTTP/1.1 100 继续 HTTP/1.1 200 正常 日期:格林威治标准时间 2009 年 7 月 1 日星期三 06:51:57 服务器: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 内容长度:51 保活:超时=5,最大值=100 连接:保持活动 内容类型:文本/html 可能的文件上传攻击:filename ''.Array ( )

我在本地 windows xp 上使用 xampp 和远程 Linux 服务器对此进行了测试。我也尝试使用以前版本的 HttpClient - 3.1 版 - 结果更不清楚,is_uploaded_file 返回了false,但是$_FILES 数组填充了正确的数据。

【问题讨论】:

  • DefaultHttpClient() 现已弃用。
  • @PranjalCholadhara 那么应该使用哪个类来代替已弃用的 DefaultHttpClient()?

标签: java php java-http-client


【解决方案1】:

好吧,我用的 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();
  }
}

注意使用 MultipartEntity。

【讨论】:

  • 支持哪个新的、受支持的 HttpComponents 版本(即 hc.apache.org 而不是 HttpClient-3.1)?我收到错误消息:“无法解析类型 org.apache.james.mime4j.message.SingleBody。它是从所需的 .class 文件中间接引用的”
  • 答案:来自hc.apache.org/downloads.cgi 的 HttpClient 4.1-alpha1 和 HttpCore 4.1-alpha1 - 支持的 Apache HttpComponents Java 代码。有了这些,错误消息就消失了:)
  • 我使用的是 4.2,但我没有 mime 包。变了吗?
  • Apache HttpComponents MIME 特性可以在 group:artifact org.apache.httpcomponents:httpmime 中找到。
【解决方案2】:

对于那些尝试使用MultipartEntity的人的更新...

org.apache.http.entity.mime.MultipartEntity 在 4.3.1 中已弃用。

您可以使用MultipartEntityBuilder 创建HttpEntity 对象。

File file = new File();

HttpEntity httpEntity = MultipartEntityBuilder.create()
    .addBinaryBody("file", file, ContentType.create("image/jpeg"), file.getName())
    .build();

对于 Maven 用户,该类在以下依赖项中可用(与 fervisa 的答案几乎相同,只是有更高版本)。

<dependency>
  <groupId>org.apache.httpcomponents</groupId>
  <artifactId>httpmime</artifactId>
  <version>4.3.1</version>
</dependency>

【讨论】:

  • 也许你应该更新接受的答案并改进它。
【解决方案3】:

正确的方法是使用多部分 POST 方法。有关客户端的示例代码,请参见 here

对于 PHP,有许多可用的教程。这是我找到的first。我建议你先用html客户端测试PHP代码,然后再试试java客户端。

【讨论】:

  • 我试图使用您提出的方法,即 HttpClient v. 3.1 并且仍然 is_uploaded_file 返回 false,但是这次 $_FILES 数组填充了正确的数据,这让我更加困惑。顺便提一句。上传正在服务器上进行,我已经使用简单的 html 表单测试了我的 upload.php 文件。
【解决方案4】:

我遇到了同样的问题,发现 httpclient 4.x 需要文件名才能与 PHP 后端一起使用。 httpclient 3.x 并非如此。

所以我的解决方案是在 FileBody 构造函数中添加一个名称参数。 ContentBody cbFile = new FileBody(file, "image/jpeg", "FILE_NAME");

希望对你有帮助。

【讨论】:

  • 感谢您的帮助。那救了我。但是应该使用的构造函数是带有 4 个参数的构造函数。 new FileBody(file,file.getName(),"application/octet-stream","UTF-8"); 3 参数构造函数将 mimetype 作为第三个参数,而不是名称。
【解决方案5】:

A newer version example is here.

以下是原代码的副本:

/*
 * ====================================================================
 * 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();
        }
    }

}

【讨论】:

    【解决方案6】:

    有我的工作解决方案,使用 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
    

    【讨论】:

      【解决方案7】:

      啊,你只需要在

      中添加一个名称参数
      FileBody constructor. ContentBody cbFile = new FileBody(file, "image/jpeg", "FILE_NAME");
      

      希望对你有帮助。

      【讨论】:

        【解决方案8】:

        我知道我迟到了,但下面是处理这个问题的正确方法,关键是使用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());
           }
        

        【讨论】:

          【解决方案9】:

          如果您在本地 WAMP 上对此进行测试,您可能需要为文件上传设置临时文件夹。您可以在 PHP.ini 文件中执行此操作:

          upload_tmp_dir = "c:\mypath\mytempfolder\"
          

          您需要授予文件夹权限才能进行上传 - 您需要授予的权限因您的操作系统而异。

          【讨论】:

          • tmp 文件夹已设置。上传正在服务器上进行,我已经使用简单的 html 表单测试了我的 upload.php 文件。
          • 你能告诉我如何用java编写服务器代码来接收httpclient请求
          【解决方案10】:

          对于那些难以实现公认答案(需要 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>
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2021-07-02
            • 1970-01-01
            • 2016-07-16
            • 1970-01-01
            • 1970-01-01
            • 2011-07-10
            • 1970-01-01
            相关资源
            最近更新 更多