golang http请求封装

本文详细介绍了如何在Golang中封装HTTPPOST请求,包括发送JSON数据和FORM数据,同时对比了使用http.Post与http.NewRequest方法的区别。此外,还展示了GET请求的封装以及如何添加自定义header。通过示例代码,演示了各种请求的测试过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http请求封装在项目中非常普遍,下面笔者封装了http post请求传json、form 和get请求,以备将来使用

1、POST请求

1.1、POST请求发送 json

这里发送json笔者使用了2种方式,一种是golang 自带的 http.Post方法,另一是 http.NewRequest

方法。二者的区别是http.Post方法不能发送自定义的header数据;而http.NewRequest方法可以发送额外的自定义header数据

先看使用golang 自带的 http.Post方法封装的POST请求

func HttpPostJson(url string, requestBody []byte) (string, error) {
	response, er := http.Post(url, "application/json", bytes.NewBuffer(requestBody))
	if er != nil {
		return "", er
	}
	defer response.Body.Close()
	body, er2 := ioutil.ReadAll(response.Body)
	if er2 != nil {
		return "", er2
	}
	return string(body), nil
}

再看使用http.NewRequest方法封装的POST请求

看golang的源代码可以知道 http.Post方法底层就是使用的 NewRequest 方法,因此NewRequest方法更加灵活

func HttpPost(url string, header map[string]string, requestBody []byte) (string, error) {
	httpClient := &http.Client{}

	request, er := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(requestBody))
	if er != nil {
		return "", er
	}

	for key, value := range header {
		request.Header.Set(key, value)
	}
	//设置请求头Content-Type
	request.Header.Set("Content-Type", "application/json")
	response, er2 := httpClient.Do(request)
	if er2 != nil {
		return "", er2
	}
	defer response.Body.Close()
	body, er3 := ioutil.ReadAll(response.Body)
	if er3 != nil {
		return "", er3
	}
	return string(body), nil
}

1.2、POST请求发送form

form数据使用map存放,map的key是字符串,value是字符串切片

func HttpPostForm(url string, form map[string][]string) (string, error) {
	response, er := http.PostForm(url, form)
	if er != nil {
		return "", er
	}
	defer response.Body.Close()
	body, er2 := ioutil.ReadAll(response.Body)
	if er2 != nil {
		return "", er2
	}
	return string(body), nil
}

可以携带自定义header的post请求发送form

笔者使用NewRequest 方法封装的可以携带自定义header的form请求

func HttpPostHeaderForm(requestUrl string, header map[string]string, form map[string][]string) (string, error) {
	httpClient := &http.Client{}
	var data url.Values
	data = map[string][]string{}
	for k, v := range form {
		data[k] = v
	}
	request, er := http.NewRequest(http.MethodPost, requestUrl, strings.NewReader(data.Encode()))
	if er != nil {
		return "", er
	}
	request.Header.Set("Content-Type", "application/x-www-form-urlencoded")

	//设置自定义header
	for key, value := range header {
		request.Header.Set(key, value)
	}

	response, er := httpClient.Do(request)
	if er != nil {
		return "", er
	}
	defer response.Body.Close()
	body, er2 := ioutil.ReadAll(response.Body)
	if er2 != nil {
		return "", er2
	}
	return string(body), nil
}

2、GET请求

func HttpGet(url string) (string, error) {
	response, er := http.Get(url)
	if er != nil {
		return "", er
	}
	defer response.Body.Close()
	body, er2 := ioutil.ReadAll(response.Body)
	if er2 != nil {
		return "", er2
	}
	return string(body), nil
}

3、测试

这里服务端笔者使用springboot项目创建,用来接收请求,端口默认8080

参数类

package com.wsjz.demo.param;

import lombok.Data;


@Data
public class AddParam {

    private String name;

    private Integer age;
}

controller

package com.wsjz.demo.controller;

import com.wsjz.demo.param.AddParam;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;

@RestController
public class DemoController {

    @PostMapping("/json/add")
    public String jsonAdd(@RequestBody AddParam param, HttpServletRequest request) {
        System.out.println(request.getHeader("token"));
        System.out.println(param);
        return "json ok";
    }

    @PostMapping("/form/add")
    public String formAdd(AddParam param, HttpServletRequest request) {
        System.out.println(request.getHeader("token"));
        System.out.println(param);
        return "form ok";
    }

    @GetMapping("/get/add")
    public String getAdd(AddParam param) {
        System.out.println(param);
        return "get ok";
    }

}

golang测试代码

新建User结构体做为参数

type User struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
}

(1)、测试HttpPostJson方法

func TestHttpPostJson(t *testing.T) {
	url := "http://localhost:8080/json/add"

	var user = User{
		Name: "举头西北浮云,倚天万里须长剑,人言此地,夜深长见,斗牛光焰",
		Age:  17,
	}
	requestBody, er := json.Marshal(user)
	if er != nil {
		log.Fatal(er)
	}
	response, er := HttpPostJson(url, requestBody)
	if er != nil {
		fmt.Println(er)
	}
	fmt.Println(response)
}

运行效果

(2)、测试HttpPost方法

func TestHttpPost(t *testing.T) {
	url := "http://localhost:8080/json/add"
	var header = make(map[string]string)
	header["token"] = "2492dc007dfc4ce8adcc8b42b21641f4"

	var user = User{
		Name: "我见青山多妩媚",
		Age:  17,
	}
	requestBody, er := json.Marshal(user)
	if er != nil {
		log.Fatal(er)
	}
	response, er2 := HttpPost(url, header, requestBody)
	if er2 != nil {
		log.Fatal(er2)
	}
	fmt.Println(response)
}

运行效果

(3)、测试HttpPostForm方法

func TestHttpPostForm(t *testing.T) {
	url := "http://localhost:8080/form/add"
	var form = make(map[string][]string)
	form["name"] = []string{"可怜今夕月,向何处,去悠悠"}
	form["age"] = []string{"18"}
	response, er := HttpPostForm(url, form)
	if er != nil {
		fmt.Println(er)
	}
	fmt.Println(response)
}

运行效果

(4)、测试HttpPostHeaderForm方法

func TestHttpPostHeaderForm(t *testing.T) {
	url := "http://localhost:8080/form/add"
	var header = make(map[string]string)
	header["token"] = "0a8b903b7d7448e3ab007caab081965c"
	var form = make(map[string][]string)
	form["name"] = []string{"相思字,空盈幅,相思意,何时足"}
	form["age"] = []string{"18"}

	response, er := HttpPostHeaderForm(url, header, form)
	if er != nil {
		fmt.Println(er)
	}
	fmt.Println(response)
}

运行效果

(5)、测试HttpGet方法

func TestHttpGet(t *testing.T) {
	//对中文进行编码
	name := url.QueryEscape("乘风好去,长空万里,直下看山河")
	requestUrl := "http://localhost:8080/get/add?name=" + name + "&age=19"
	response, er := HttpGet(requestUrl)
	if er != nil {
		fmt.Println(er)
	}
	fmt.Println(response)
}

运行效果

至此完

### 封装HTTP接口的最佳实践 在Go语言中,封装HTTP接口通常涉及创建结构体来表示服务客户端,并实现相应的方法来进行API调用。为了提高测试性和可维护性,建议遵循以下最佳实践: #### 使用接口定义行为 通过定义接口可以更容易地切换不同的实现方式以及简化单元测试过程。例如,如果有一个名为`ClientInterface`的接口用于描述所有预期的行为,则可以在实际应用里注入具体的实例,在测试环境中替换为模拟对象。 ```go type ClientInterface interface { GetUsers() ([]User, error) } ``` #### 创建具体的服务客户端 基于上述接口构建一个真实的网络请求处理者。这里会利用标准库中的`net/http`包发起GET请求并解析响应数据。 ```go import ( "encoding/json" "io/ioutil" "net/http" ) // RealClient implements ClientInterface with actual API calls. type RealClient struct{} func (c *RealClient) GetUsers() ([]User, error) { resp, err := http.Get("https://api.example.com/users") // 发送 GET 请求到指定 URL if err != nil { return nil, err } defer resp.Body.Close() bodyBytes, readErr := ioutil.ReadAll(resp.Body) if readErr != nil { return nil, readErr } var users []User json.Unmarshal(bodyBytes, &users) // 解析 JSON 响应内容 return users, nil } type User struct { // 用户模型 ID int `json:"id"` Name string `json:"name"` } ``` #### 编写测试案例 当涉及到外部依赖项时(如远程服务器),应该考虑使用像[gock][^1]这样的工具来自动生成匹配规则或录制交互记录以便离线重放;也可以采用[mockhttp]作为替代方案之一,它允许开发者轻松伪造`http.ResponseWriter`的行为从而更好地控制返回给客户端的数据形式。 对于更复杂的场景下可能还需要借助于[gomock]框架自动生成桩函数代码片段,进而达到更加灵活多变的效果。 ```go package main_test import ( . "github.com/your-repo-name/main" "testing" gock "gopkg.in/h2non/gock.v1" ) func TestGetUsers(t *testing.T) { mockJSONResponse := `[{"id": 1,"name":"John Doe"}]` gock.New("https://api.example.com"). Get("/users").Reply(200).BodyString(mockJSONResponse) client := new(RealClient) result, _ := client.GetUsers() expected := []User{{ID: 1, Name: "John Doe"}} if !reflect.DeepEqual(result, expected){ t.Errorf("Expected %v but got %v",expected,result) } gock.Off() // 清理所有的 mocks 和 matchers } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

悟世君子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值