没有前端页面如何发HTTP请求?Go http client给你答案

293 阅读2分钟

在开发的过程中,难免会调用其他的开发组的API,有时候这些API提供的是http接口或者是RPC接口,当服务是http接口时,如果需要在后端请求接口,那么则需要通过http client来发送请求

请求场景

  • 上传文件的同时,还需要附带请求参数
  • 发送JSON请求体

整体思路

  • 将请求内容放入到一个输出流中
  • 将输出流作为请求的参数
  • 发送请求

请求参数+文件上传

  • 准备一个buffer用于缓冲请求参数和文件
  • 创建一个multipartWriter,用于写请求参数和文件
  • 在writer中写请求参数和文件
  • 发送请求

如果你想上传一个文件,附带一个对文件的描述,在HTML中它是这样的

<form
    action="http://upload.com/post"
    method="post"
    enctype="multipart/form-data"
>
  <input type="text" name="description"/>
  <input type="file" name="fileName">
  <input type="submit">
</form>

话不多说上代码

func uploadFile(fileName string, targetUrl string) error {
	bodyBuf := &bytes.Buffer{}
	bw := multipart.NewWriter(bodyBuf)
  //模拟表单中的text字段
	bw.WriteField("description", "一本好书")
	//模拟表单中文件上传的字段
	fileWriter, err := bw.CreateFormFile("fileName", fileName)
	if err != nil {
		fmt.Println("write to buffer error")
		return err
	}
	//打开需要上传的文件
	fh, err := os.Open(fileName)
	if err != nil {
		fmt.Println("open file error")
		return err
	}
	defer fh.Close()

	//将文件流copy到创建好的文件上传流中
	_, err = io.Copy(fileWriter, fh)
	if err != nil {
		return err
	}
	//multipart/form-data
	contentType := bw.FormDataContentType()
	bw.Close()
	//发送请求
	resp, err := http.Post(targetUrl, contentType, bodyBuf)
	if err != nil {
		return err
	}
	defer resp.Body.Close()
	respBody, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return err
	}
	fmt.Println(respBody)
	return nil
}

发送JSON数据

  • 创建JSON编码器
  • 将结构体编码到字节流
  • 将字节流作为请求参数
  • 发送请求
//服务端
func Handeler(respWriter http.ResponseWriter, req *http.Request) {
	if req.Method == "POST" {
		msg := Msg{}
		json.NewDecoder(req.Body).Decode(&msg)
		fmt.Println("des:", msg.Description)
	}
	respWriter.Write([]byte("every thing is ok!"))
}
func main() {
	http.HandleFunc("/test", Handeler)
	http.ListenAndServe(":8080", nil)
}

//客户端
type Msg struct {
	Description string `json:"description"`
}
func main() {
	msg := Msg{"test"}
	bf := &bytes.Buffer{}
  //创建JSON编码器并编码struct结构体
	err := json.NewEncoder(bf).Encode(msg)
	if err != nil {
		fmt.Println("encoding error")
		os.Exit(-1)
	}
  //发送请求
	req, err := http.NewRequest("POST", "http://localhost:8080/test", bf)
	client := &http.Client{
		Timeout: time.Millisecond * 100,
	}
	resp, err := client.Do(req)
	fmt.Println(resp.Status)
	resByte, _ := ioutil.ReadAll(resp.Body)
	fmt.Println(string(resByte))
}

踩坑

  • http.Response的Body需要用ioutil去读取
    • 不是直接调用resp.Body.read()方法,这样做会读不到响应内容。Body.read()是当网络连接失败或者服务端终止了请求响应,此时会返回error