[Android] 如何發送包含File data的POST Request(以Image Upload為例)
(How to build a multipart POST request)
Multipart POST是一種可傳送包含binary data的POST method,網頁中最常見的例子就是帶有附加檔案的Form,以下範例將說明在Android中如何透過HttpClient發送一個含有Image與字串的multipart POST。
程式碼說明
1. 下載HttpMIME Library
雖然Android有把HttpClient納入framework,但不包含HttpMIME,有了HttpMIME lib我們才可以進行multipart POST。
網址:http://hc.apache.org/downloads.cgi
下載後將.jar加入Project library(Project右鍵→Properties→Java Build Path→Add External JAR)
2. 定義程式Layout
這裡會定義一個簡單的form,包含一個TextView表示String data,另一個TextView代表attached file path,當User按下submit按鈕將會將form data透過multipart post將data送至後端(檔案的部份為了Demo方便所以以寫死的file path表示,其實可以再加入file browse的功能)。
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" android:gravity="center_horizontal" > <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:layout_width="130dp" android:layout_height="wrap_content" android:text="file Description:"/> <EditText android:id="@+id/desTxt" android:layout_width="160dp" android:layout_height="wrap_content" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:layout_width="130dp" android:layout_height="wrap_content" android:text="File path:"/> <EditText android:id="@+id/filePath" android:layout_width="160dp" android:layout_height="wrap_content" /> </LinearLayout> <Button android:id="@+id/submitBtn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Submit" android:onClick="onSubmit" /> </LinearLayout>3. 實作multipart post function
以HttpClient進行POST呼叫,並透過MultipartEntity加入欲傳遞的data,data大致分兩種類型String part與File part,都透過addPart方法附加參數至POST Request,最後再透過ResponseHandler取得Server端回應。
private void doMultiPost(String url, List< NameValuePair> params){
HttpClient client=new DefaultHttpClient();
HttpPost post=new HttpPost(url);
try{
//setup multipart entity
MultipartEntity entity=new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
for(int i=0;i< params.size();i++){
//identify param type by Key
if(params.get(i).getName().equals("file")){
File f=new File(params.get(i).getValue());
FileBody fileBody=new FileBody(f);
entity.addPart("image"+i,fileBody);
}else{
entity.addPart(params.get(i).getName(),new StringBody(params.get(i).getValue(), ContentType.TEXT_PLAIN));
}
}
post.setEntity(entity);
//create response handler
ResponseHandler< String> handler=new BasicResponseHandler();
//execute and get response
String response=new String(client.execute(post,handler).getBytes(),HTTP.UTF_8);
Toast.makeText(this, response, Toast.LENGTH_SHORT).show();
}catch(Exception e){
e.printStackTrace();
}
}
4.Submit button click handler
public void onSubmit(View v){
String path=((EditText)findViewById(R.id.filePath)).getText().toString();
String des=((EditText)findViewById(R.id.desTxt)).getText().toString();
List< NameValuePair> params = new ArrayList< NameValuePair>();
params.add(new BasicNameValuePair("file",path));
params.add(new BasicNameValuePair("des",des));
doMultiPost("yourhost/MultipartPost.php",params);
}
4. 後端程式碼(以PHP為例)//get http request parameters
if(move_uploaded_file($_FILES['image0']['tmp_name'], $_FILES['image0']['name'])){
print_r("File".$_FILES['image0']['name']." is valid, and was successfully uploaded");
}else{
print_r('Pic:'.$_FILES['image0']['name'].' Uploaded unsuccessfully!');
}

請教一下,php端如果要存圖的話,就直接針對$image0作處理嗎?
回覆刪除不好意思,之前貼到另一個檔案的內容,新更新的後端程式就示範了如何儲存上傳後的檔案
回覆刪除很實用的文章,感謝!
回覆刪除之前也用這個方法,在傳中文vars的時候會遇到亂碼。
提供一個小建議:
在第15行的:entity.addPart(params.get(i).getName(),new StringBody(params.get(i).getValue()));
更改為:
entity.addPart(params.get(i).getName(),new StringBody(params.get(i).getValue(), Charset.forName("UTF-8")));
強制採UTF-8來傳vars就不會有亂碼了。
也提供其它朋友參考。
謝謝cupid大的補充,本來的寫法的確會造成中文亂碼的問題,已更新至文章中,感謝!
回覆刪除感謝你分享這篇文章,幫助了我很多!
回覆刪除@Cryus 不客氣,我只是簡單分享自己的經驗,能幫助到你,我覺得很棒!
回覆刪除請教一下,我在new Strinbody的時候會有刪除線,是什麼原因呢?
回覆刪除@陳禹凡 原因在於 Stringbody(String text, Charset charset) 已經被 deprecated 了,請使用 Stringbody(String text, ContentTypes contentType),例如:new Stringbody(params.get(i).getValue(), ContentType.TEXT_PLAIN),文件請參考 https://hc.apache.org/httpcomponents-client-ga/httpmime/apidocs/org/apache/http/entity/mime/content/StringBody.html
回覆刪除