项目有个需求就是需要上传文件,由于传文件要用到multipart/data-form这种content-type。
里面内容全是2进制,各个field需要自己去拼。今天上午用java的HttpUrlConnection那个类自己去做,结果一上午都没做出来,服务器一直报错,拿浏览器提交就一点问题也没有。对比浏览器的报文,眼睛都看花了也没觉得哪里不一样。于是下午就开始尝试HttpClient。
在Apache上下了个最新的用JAVA玩没什么问题,放到jar包安卓上就开始各种类找不到…
经过长时间网上搜索,发现android是自带apache httpclient的,但是它自带的那个不全,无法发文件。如果要发文件要用到 apache-mime4j-0.6.jar httpmime-4.0.1.jar 这两个jar包,缺一不可!把这两个加到build path里面就ok了。
安卓端文件上传源码如下:
package com.example.uploadtest;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
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.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import android.app.Activity;
import android.content.res.AssetManager;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Button button = new Button(this);
setContentView(button);
button.setText("send data and write file");
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
new Thread(new NetWorUpload(getAssets())).start();
}
});
}
class NetWorUpload implements Runnable {
AssetManager assetManager;
public NetWorUpload(AssetManager assetManager) {
this.assetManager = assetManager;
}
@Override
public void run() {
HttpClient client = new DefaultHttpClient();
HttpPost postMethod = new HttpPost("http://192.168.1.101:8080/upload");
File file = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) ;
String picturePath= file.getAbsolutePath();
try {
byte[] buffer=new byte[1024*10];
InputStream is=assetManager.open("one.jpg");
File output=new File(picturePath+"/one.jpg");
Log.d("MSG", output.getAbsolutePath());
FileOutputStream fos=new FileOutputStream(output);
int readCount=0;
Log.d("MSG",is.available()+"");
while((readCount=is.read(buffer))!=-1 ){
fos.write(buffer,0,readCount);
Log.i("MSG", readCount+"");
}
fos.close();
MultipartEntity entity = new MultipartEntity();
FileBody contentFile = new FileBody(output);
entity.addPart("uploadFile",contentFile);
StringBody username = new StringBody("Longyubo");
entity.addPart("username",username);
StringBody password=new StringBody("passsss");
entity.addPart("password", password);
postMethod.setEntity(entity);
HttpResponse response = client.execute(postMethod);
HttpEntity httpEntity = response.getEntity();
String state = EntityUtils.toString(httpEntity);
Log.i("MSG", state);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
需要自己放个one.jpg到asset里面
Go服务器端源码如下:
那个login是用来测试一个post表单中,多个value匹配一个name的情况。。。可以不用管哈
// FileUploadServer project main.go
package main
import (
"fmt"
"html/template"
"io"
"net/http"
"os"
)
func printErr(e error) {
if e != nil {
fmt.Println(e)
}
}
//测试多个值的时候情况
func login(w http.ResponseWriter, r *http.Request) {
if r.Method == "GET" {
hello, world := "hello", "world"
t, err := template.ParseFiles("login.html")
if err != nil {
fmt.Println(err)
}
t.Execute(w, map[string]string{"hello": hello, "world": world})
} else {
r.ParseForm()
for _, v := range r.Form["username"] {
w.Write([]byte("username: " + v))
}
w.Write([]byte("\n"))
for _, v := range r.Form["password"] {
w.Write([]byte("password: " + v))
}
}
}
func upload(w http.ResponseWriter, r *http.Request) {
fmt.Println("uplaod invoke")
if r.Method == "GET" {
tpl, err := template.ParseFiles("upload.html")
if err != nil {
fmt.Println(err)
}
tpl.Execute(w, nil)
} else {
fmt.Println(r.Header)
reader, _ := r.MultipartReader()
form, FormErr := reader.ReadForm(16 << 20)
if FormErr != nil {
fmt.Println("FormErr", FormErr)
}
values:= form.Value
for k,v:=range values{
w.Write([]byte("server recieve--name: "+k+" value: "+v[0]))
}
path := "E:/upload/goUpload/"
_, statError := os.Stat(path)
if statError != nil {
os.MkdirAll(path, 0777)
}
fmt.Println("BEFORE UPLOAD LIST")
fmt.Println("form", form.File["uploadFile"])
fileheadList := form.File["uploadFile"]
fmt.Println("AFTER UPLOAD LIST")
for _, v := range fileheadList {
fileName := v.Filename
file, err := v.Open()
printErr(err)
defer file.Close()
toFile, fileError := os.Create(path + fileName)
if fileError != nil {
printErr(fileError)
break
}
defer toFile.Close()
io.Copy(toFile, file)
w.Write([]byte("server had write file : " + fileName + "\n"))
}
w.Write([]byte("server had recieve your data successfully"))
}
}
func main() {
http.HandleFunc("/login", login)
http.HandleFunc("/upload", upload)
err := http.ListenAndServe(":8080", nil)
if err != nil {
fmt.Println(err)
}
}
整个工程android和服务器端都上传了csdn。下载地址 http://download.youkuaiyun.com/detail/longyubo007/7605259