人生如逆旅,我亦是行人
今天一个后端同学问我客户端图片上传如何处理,把思路和代码告诉他后,但是他对后端如何处理文件数据还是不太了解,正好我对后端的文件接收也没有处理过,借此机会自己动手走一次前后端上传和接收的整个流程,换个角度看看问题。客户端代码以kotlin为例,服务端代码以go为例:
一. 网段的配置
1、首先保证手机和mac在同一个wifi下,终端输入ifconfig获取本机ip
image.png
2、手机设置wifi为为手动代理,ip填写刚才获取到的mac地址,端口填写7777
image.png
二、Android端文件的上传(以图片为例):
详细情况可以参考我另外一篇博客:https://www.jianshu.com/p/3a665b2e6d5b
@Multipart
@POST("api/rq_info_add_submit")
fun upload(@Part() parts: List<MultipartBody.Part>): Observable<HttpResult<String>>
private fun uploadImages(imgPaths: List<String>) {
val builder = MultipartBody.Builder()
builder.setType(MultipartBody.FORM)
val imgFile = File(imgPaths[0])
val imgBody = RequestBody.create(MediaType.parse("multipart/form-data"), imgFile1)
builder.addFormDataPart("first_photo", imgFile.name, imgBody)
var map: TreeMap<String, String> = HttpClient.instance.getBaseMap(true)
map["type"] = type.toString()
map["name"] = name
map["number"] = number
map = DataHandler.encryptParams(map) as TreeMap<String, String>
map.forEach {
builder.addFormDataPart(it.key, it.value)
}
val parts = builder.build().parts()
HttpClient.instance.upload(parts)
.compose(SchedulerHelpers.io2main())
.bindToLifecycle(this)
.subscribe {
}
}
三、服务端接收并解析:
package main
import (
"fmt"
"io"
"log"
"net/http"
"os"
)
func httpHandler(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("hello"))
log.Println(r)
r.ParseMultipartForm(32 << 20)
file, handler, err := r.FormFile("images")//获取MultipartForm中字段为images的文件
if err != nil {
fmt.Println(err)
return
}
defer file.Close()
fmt.Fprintf(w, "%v", handler.Header)
f, err := os.OpenFile("./test.jpg", os.O_WRONLY|os.O_CREATE, 0666)
//将文件保存为test.jpg
if err != nil {
fmt.Println(err)
return
}
defer f.Close()
io.Copy(f, file)
}
func main() {
http.HandleFunc("/api/rq_info_add_submit", httpHandler)
http.ListenAndServe("0.0.0.0:7777", nil)
}
获取GET请求参数
queryForm, err := url.ParseQuery(r.URL.RawQuery)
if err == nil && len(queryForm["id"]) > 0 {
fmt.Fprintln(w, queryForm["id"][0])
}
获取POST请求参数
application/x-www-form-urlencoded 格式
r.ParseForm()
// 法一
r.PostForm["id"][0]
// 法二
r.PostFormValue["id"]
multipart/form-data 格式
普通参数
r.ParseMultipartForm(32<<20)
// 法一
r.PostForm["id"][0]
// 法二
r.PostFormValue["id"]
文件
r.ParseMultipartForm(32 << 20)
file, handler, err := r.FormFile("file")
if err != nil {
fmt.Println(err)
return
}
defer file.Close()
fmt.Fprintf(w, "%v", handler.Header)
f, err := os.OpenFile("./test.txt", os.O_WRONLY|os.O_CREATE, 0666)
if err != nil {
fmt.Println(err)
return
}
defer f.Close()
io.Copy(f, file)
application/json 格式
type User struct {
Name string `json:"username"`
Pwd string `json:"password"`
}
type RetMessage struct {
Code string `json:"code"`
Msg string `json:"msg"`
}
func processJson(w http.ResponseWriter, r *http.Request) {
var u User
if r.Body == nil {
http.Error(w, "Please send a request body", 400)
return
}
err := json.NewDecoder(r.Body).Decode(&u)
if err != nil {
http.Error(w, err.Error(), 400)
return
}
fmt.Println(u)
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(RetMessage{"200", "ok"})
}
网友评论