开发Golang接口Mock服务可以快速解决接口开发测试阶段的依赖问题,通过自定义响应配置和规则匹配,能够模拟各种真实接口的场景,满足不同测试需求。

Golang接口Mock服务基础搭建
首先我们需要搭建一个基础的HTTP服务作为Mock服务的载体,使用Golang标准库的net/http包即可快速实现。下面的代码实现了一个最基础的Mock服务框架,能够接收所有HTTP请求并返回默认响应。
package main
import (
"fmt"
"net/http"
)
// 默认处理函数,返回基础Mock响应
func defaultHandler(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
// 默认返回简单的JSON响应
fmt.Fprintf(w, `{"code": 200, "msg": "default mock response"}`)
}
func main() {
// 注册所有路径的处理函数
http.HandleFunc("/", defaultHandler)
// 启动服务监听8080端口
fmt.Println("Mock服务启动,监听端口8080")
http.ListenAndServe(":8080", nil)
}
Mock响应配置实现
响应配置需要支持自定义状态码、响应头、响应体等内容,我们可以定义一个配置结构体来存储这些信息,然后在处理请求时读取配置返回对应内容。
响应配置结构体定义
首先定义响应配置的结构体,包含响应需要的各个字段:
package main
// ResponseConfig 定义Mock响应配置
type ResponseConfig struct {
StatusCode int `json:"status_code"` // HTTP状态码
Headers map[string]string `json:"headers"` // 响应头
Body string `json:"body"` // 响应体内容
}
加载响应配置
我们可以将响应配置存储在JSON文件中,服务启动时加载配置,下面是实现配置加载的代码:
package main
import (
"encoding/json"
"os"
)
// LoadResponseConfig 从JSON文件加载响应配置
func LoadResponseConfig(filePath string) (*ResponseConfig, error) {
data, err := os.ReadFile(filePath)
if err != nil {
return nil, err
}
var config ResponseConfig
err = json.Unmarshal(data, &config)
if err != nil {
return nil, err
}
return &config, nil
}
应用响应配置
修改之前的处理函数,读取配置并应用响应配置:
package main
import (
"fmt"
"net/http"
)
// 全局响应配置变量
var globalRespConfig *ResponseConfig
func configHandler(w http.ResponseWriter, r *http.Request) {
// 设置响应状态码
w.WriteHeader(globalRespConfig.StatusCode)
// 设置响应头
for key, value := range globalRespConfig.Headers {
w.Header().Set(key, value)
}
// 写入响应体
fmt.Fprintf(w, globalRespConfig.Body)
}
func main() {
// 加载响应配置
config, err := LoadResponseConfig("response_config.json")
if err != nil {
fmt.Println("加载响应配置失败:", err)
return
}
globalRespConfig = config
// 注册处理函数
http.HandleFunc("/", configHandler)
fmt.Println("Mock服务启动,监听端口8080")
http.ListenAndServe(":8080", nil)
}
对应的response_config.json文件内容示例如下:
{
"status_code": 200,
"headers": {
"Content-Type": "application/json",
"X-Mock-Sign": "test"
},
"body": "{"code": 200, "data": {"id": 1, "name": "test user"}, "msg": "success"}"
}
规则匹配实现
规则匹配需要根据请求的不同特征返回不同的响应,常见的匹配维度包括请求路径、请求方法、请求参数、请求头、请求体等。我们可以定义匹配规则结构体,然后遍历规则找到匹配的项返回对应响应。
规则匹配结构体定义
定义规则结构体和对应的响应映射:
package main
// MatchRule 定义匹配规则
type MatchRule struct {
Path string `json:"path"` // 请求路径
Method string `json:"method"` // 请求方法 GET POST等
Params map[string]string `json:"params"` // 查询参数匹配
Headers map[string]string `json:"headers"` // 请求头匹配
ResponseBody string `json:"request_body"` // 请求体匹配内容
}
// RuleGroup 规则组,包含规则和对应响应
type RuleGroup struct {
Rules []MatchRule `json:"rules"`
Response ResponseConfig `json:"response"`
}
规则匹配逻辑实现
实现请求匹配逻辑,遍历所有规则找到第一个匹配的规则返回对应响应:
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"strings"
)
// 全局规则组列表
var ruleGroups []RuleGroup
// 匹配请求参数
func matchParams(r *http.Request, ruleParams map[string]string) bool {
if len(ruleParams) == 0 {
return true
}
queryParams := r.URL.Query()
for key, value := range ruleParams {
if queryParams.Get(key) != value {
return false
}
}
return true
}
// 匹配请求头
func matchHeaders(r *http.Request, ruleHeaders map[string]string) bool {
if len(ruleHeaders) == 0 {
return true
}
for key, value := range ruleHeaders {
if r.Header.Get(key) != value {
return false
}
}
return true
}
// 匹配请求体
func matchRequestBody(r *http.Request, ruleBody string) bool {
if ruleBody == "" {
return true
}
body, err := io.ReadAll(r.Body)
if err != nil {
return false
}
// 重新设置请求体,避免后续读取为空
r.Body = io.NopCloser(bytes.NewBuffer(body))
return strings.Contains(string(body), ruleBody)
}
// 规则匹配处理函数
func ruleMatchHandler(w http.ResponseWriter, r *http.Request) {
// 遍历所有规则组
for _, group := range ruleGroups {
for _, rule := range group.Rules {
// 匹配路径
if rule.Path != "" && r.URL.Path != rule.Path {
continue
}
// 匹配请求方法
if rule.Method != "" && strings.ToUpper(r.Method) != strings.ToUpper(rule.Method) {
continue
}
// 匹配参数
if !matchParams(r, rule.Params) {
continue
}
// 匹配请求头
if !matchHeaders(r, rule.Headers) {
continue
}
// 匹配请求体
if !matchRequestBody(r, rule.RequestBody) {
continue
}
// 所有规则匹配成功,返回对应响应
w.WriteHeader(group.Response.StatusCode)
for key, value := range group.Response.Headers {
w.Header().Set(key, value)
}
fmt.Fprintf(w, group.Response.Body)
return
}
}
// 没有匹配的规则,返回默认响应
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
fmt.Fprintf(w, `{"code": 404, "msg": "no matching mock rule"}`)
}
func main() {
// 加载规则配置,这里简化为直接初始化,实际可以从文件加载
ruleGroups = []RuleGroup{
{
Rules: []MatchRule{
{
Path: "/user/info",
Method: "GET",
Params: map[string]string{"id": "1"},
},
},
Response: ResponseConfig{
StatusCode: 200,
Headers: map[string]string{"Content-Type": "application/json"},
Body: `{"code":200,"data":{"id":1,"name":"张三","age":20}}`,
},
},
{
Rules: []MatchRule{
{
Path: "/user/update",
Method: "POST",
Headers: map[string]string{"Content-Type": "application/json"},
RequestBody: `"name":"李四"`,
},
},
Response: ResponseConfig{
StatusCode: 200,
Headers: map[string]string{"Content-Type": "application/json"},
Body: `{"code":200,"msg":"更新成功"}`,
},
},
}
http.HandleFunc("/", ruleMatchHandler)
fmt.Println("Mock服务启动,监听端口8080")
http.ListenAndServe(":8080", nil)
}
总结
以上就是开发Golang接口Mock服务的完整流程,从基础HTTP服务搭建,到响应配置的实现,再到多维度规则匹配的逻辑开发,都给出了可运行的代码示例。开发者可以根据自己的需求扩展更多匹配维度,比如请求体JSON字段匹配、路径参数匹配等,也可以添加配置热更新、日志打印等功能,让Mock服务更贴合实际使用场景。