前言
你想处理一个由用户上传的文件,比如你正在建设一个类似 Instagram 的网站,你需要存储用户拍摄的照片。这种需求该如何实现呢?
package main
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"log"
"mime/multipart"
"net/http"
"os"
)
func postFile(filename string, target_url string) (*http.Response, error) {
body_buf := bytes.NewBufferString("")
body_writer := multipart.NewWriter(body_buf)
// use the body_writer to write the Part headers to the buffer
_, err := body_writer.CreateFormFile("file", filename)
if err != nil {
fmt.Println("error writing to buffer")
return nil, err
}
// the file data will be the second part of the body
fh, err := os.Open(filename)
if err != nil {
fmt.Println("error opening file")
return nil, err
}
// need to know the boundary to properly close the part myself.
boundary := body_writer.Boundary()
//close_string := fmt.Sprintf("\r\n--%s--\r\n", boundary)
close_buf := bytes.NewBufferString(fmt.Sprintf("\r\n--%s--\r\n", boundary))
// use multi-reader to defer the reading of the file data until
// writing to the socket buffer.
request_reader := io.MultiReader(body_buf, fh, close_buf)
fi, err := fh.Stat()
if err != nil {
fmt.Printf("Error Stating file: %s", filename)
return nil, err
}
req, err := http.NewRequest("POST", target_url, request_reader)
if err != nil {
return nil, err
}
// Set headers for multipart, and Content Length
req.Header.Add("Content-Type", "multipart/form-data; boundary="+boundary)
req.ContentLength = fi.Size() + int64(body_buf.Len()) + int64(close_buf.Len())
return http.DefaultClient.Do(req)
}
// sample usage
func main() {
target_url := "http://localhost:9000/ai/v1/speech/asr"
filename := "test.wav"
rep, _ := postFile(filename, target_url)
content, _ := ioutil.ReadAll(rep.Body)
log.Println("get response: " + string(content))
}
返回结果
返回的是map + list的形式,现在我们创建一个结构体去接收该数据。
type CommonMsg struct {
Code string `json:"code"` // 通用消息代码
Data NotifyMsg `json:"data"` // 通用消息数据
RequestId string `json:"requestId"` // 请求ID
}
type NotifyMsg struct {
Sentences []List `json:"sentences"` // 应用列表
}
type List struct {
AverageVolume float64 `json:"averageVolume"` // 应用代码
EndTime int64 `json:"endTime"` // 应用名称
MaxVolume float64 `json:"maxVolume"` // 应用URL
StartTime int64 `json:"startTime"` // 应用URL
Text string `json:"text"` // 应用URL
}
读取数据,将返回的数据,解析成msg结构体。
var msg CommonMsg
body, _ := ioutil.ReadAll(rep.Body)
json.Unmarshal(body, &msg)
fmt.Println(msg)
总结
上面的例子详细展示了客户端如何向服务器上传一个文件的例子,客户端通过把文件的文本流写入一个缓存中,然后调用 http 的 Post 方法把缓存传到服务器。