golang系列——实战http上传文件 | 已验证

203 阅读1分钟

前言

你想处理一个由用户上传的文件,比如你正在建设一个类似 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))
}

返回结果

323.png

返回的是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 方法把缓存传到服务器。

参考

blog.51cto.com/u_13571520/…

learnku.com/docs/build-…