[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
回覆刪除