Android使用MultipartEntityBuilder實現相似form表單提交方式的文件上傳

      最近在作 Android 端文件上傳,要求採用 form 表單的方式提交,項目使用的 afinal 框架有文件上傳功能,可是始終沒法與php寫的服務端對接上,沒法上傳成功。讀源碼發現:afinal 使用了某大神寫的 MultipartEntity.java 生成 form 表單內容,然而生成的內容格式不夠標準,並且還存在諸多問題,如:首先將全部文件讀入到內存,再生成字節流寫入到 socket。那麼問題來了:若是是幾百MB的文件怎麼辦?php

      幾番搜索,受到 這篇文章(已被我轉載,可是示例代碼已過時的啓發,我展轉找到了 Apache 源碼 httpcomponents-client-4.3.6-src.zip,在一個示例裏面發現了一個重要的組件 MultipartEntityBuilder, 能夠生成 form 表單格式的 HttpEntity, 有了 HttpEntity, 不管你是什麼 http 框架,應該均可以使用。java


不知道怎麼使用?like this:
git

HttpPost httppost = new HttpPost(url);
...
final HttpEntity entity = makeMultipartEntity(params, files);
httppost.addHeader(entity.getContentType());
//httppost.addHeader(entity.getContentEncoding());    //null
httppost.setEntity(entity);
HttpResponse response = getHttpClient().execute(httppost);
...

private static HttpClient mClient;
private static HttpClient getHttpClient() {
    if(mClient == null) {
        //if(Build.VERSION.SDK_INT >= 9);    //將不走本類的Case,基於HttpURLConnection
        if(Build.VERSION.SDK_INT >= 8) {
            mClient = AndroidHttpClient.newInstance(getUserAgent());
        }else {
            mClient = new DefaultHttpClient();
        }
    }
    return mClient;
}

MultipartEntityBuilder 用法整理以下:
github

須要用到 httpcomponents-client-4.3.6-bin.zip 中的 httpmime-4.3.6.jar 和 httpcore-4.3.3.jarexpress

public static HttpEntity makeMultipartEntity(List<NameValuePair> params, final Map<String, File> files) {
    MultipartEntityBuilder builder = MultipartEntityBuilder.create();
    builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);	//若是有SocketTimeoutException等狀況,可修改這個枚舉
    //builder.setCharset(Charset.forName("UTF-8"));	//不要用這個,會致使服務端接收不到參數
    if (params != null && params.size() > 0) {
        for (NameValuePair p : params) {
            builder.addTextBody(p.getName(), p.getValue(), ContentType.TEXT_PLAIN.withCharset("UTF-8"));
        }
    }
    if (files != null && files.size() > 0) {
        Set<Entry<String, File>> entries = files.entrySet();
        for (Entry<String, File> entry : entries) {
            builder.addPart(entry.getKey(), new FileBody(entry.getValue()));
        }
    }
    return builder.build();
}


另附上 Apache 示例,可在 httpcomponents-client-4.3.6-bin.zip 中找到。
apache

/*
 * ====================================================================
 * 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();
        }
    }
}
相關文章
相關標籤/搜索