You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Go编辑WireMock动态JSON映射数据?

动态WireMock映射JSON的URL修改实现

问题场景

我需要实现一个服务,接收结构不固定的WireMock映射数据,修改其中所有request.url的值(比如在原URL前添加/geronimo前缀)后返回。WireMock的映射结构主要有两种形式:

单映射结构

{
    "request": {
        "method": "GET",
        "url": "/some/thing"
    },
    "response": {
        "status": 200,
        "body": "Hello world!",
        "headers": {
            "Content-Type": "text/plain"
        }
    }
}

多映射数组结构

{
    "mappings": [
        {
            "request": {
                "method": "GET",
                "url": "/one"
            },
            "response": {
                "status": 200
            }
        },
        {
            "id": "8c5db8b0-2db4-4ad7-a99f-38c9b00da3f7",
            "request": {
                "url": "/two"
            },
            "response": {
                "status": 200,
                "body": "Body content"
            }
        }
    ],
    "importOptions": {
        "duplicatePolicy": "IGNORE",
        "deleteAllNotInImport": true
    }
}

我已经用json.Unmarshal将JSON解析到map[string]interface{}中,但不清楚如何替换url的取值,现有代码如下:

package main

import (
    "encoding/json"
    "errors"
    "fmt"
    "io"
    "log"
    "net/http"
)

var anytype map[string]interface{}

func parseMappings() {

}

func parseReq(req map[string]interface{}) (string, error) {
    fmt.Printf("%T %v\n", req, req)
    for k, v := range req {
        if k == "url" {
            if v, ok := v.(string); ok {
                return ("/geronimo" + v), nil
            }
            return "", errors.New("Not a string")
        }
    }
    return "", nil

}

func handler(w http.ResponseWriter, req *http.Request) {
    payload, err := io.ReadAll(req.Body)
    if err != nil {
        log.Fatal(err)
    }
    err = json.Unmarshal(payload, &anytype)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%T %v\n", anytype, anytype)
    for k, v := range anytype {
        if k == "request" {
            if v, ok := v.(map[string]interface{}); ok {
                s, err := parseReq(v)
                if err != nil {
                    log.Fatal(err)
                }
                // what to do here? how replace url with new value?
                // url = s
                fmt.Println("Done", s)

            }
        } else {
            fmt.Printf("%v %T\n", k, v)
        }
    }

}

func main() {
    http.HandleFunc("/", handler)
    http.ListenAndServe(":8080", nil)
}

解决方案

针对动态JSON结构的修改,核心思路是直接操作map[string]interface{}和切片,遍历所有可能存在request.url的位置并修改:

1. 修改URL处理函数:直接操作原映射

不需要返回新URL字符串,直接在传入的request映射上修改url字段:

func modifyReqURL(req map[string]interface{}) error {
    urlVal, ok := req["url"].(string)
    if !ok {
        return errors.New("url field is not a string")
    }
    req["url"] = "/geronimo" + urlVal
    return nil
}

2. 兼容两种映射结构的处理逻辑

在请求处理函数中,同时处理顶层request字段和mappings数组中的每个request:

func handler(w http.ResponseWriter, req *http.Request) {
    payload, err := io.ReadAll(req.Body)
    if err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }

    var data map[string]interface{}
    err = json.Unmarshal(payload, &data)
    if err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }

    // 处理顶层的request
    if reqMap, ok := data["request"].(map[string]interface{}); ok {
        if err := modifyReqURL(reqMap); err != nil {
            http.Error(w, err.Error(), http.StatusBadRequest)
            return
        }
    }

    // 处理mappings数组中的每个request
    if mappings, ok := data["mappings"].([]interface{}); ok {
        for _, item := range mappings {
            if mappingMap, ok := item.(map[string]interface{}); ok {
                if reqMap, ok := mappingMap["request"].(map[string]interface{}); ok {
                    if err := modifyReqURL(reqMap); err != nil {
                        http.Error(w, err.Error(), http.StatusBadRequest)
                        return
                    }
                }
            }
        }
    }

    // 将修改后的数据序列化为JSON并返回
    modifiedJSON, err := json.MarshalIndent(data, "", "    ")
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }

    w.Header().Set("Content-Type", "application/json")
    w.Write(modifiedJSON)
}

3. 完整修改后的代码

package main

import (
    "encoding/json"
    "errors"
    "io"
    "net/http"
)

func modifyReqURL(req map[string]interface{}) error {
    urlVal, ok := req["url"].(string)
    if !ok {
        return errors.New("url field is not a string")
    }
    req["url"] = "/geronimo" + urlVal
    return nil
}

func handler(w http.ResponseWriter, req *http.Request) {
    payload, err := io.ReadAll(req.Body)
    if err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }

    var data map[string]interface{}
    err = json.Unmarshal(payload, &data)
    if err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }

    // 处理顶层request
    if reqMap, ok := data["request"].(map[string]interface{}); ok {
        if err := modifyReqURL(reqMap); err != nil {
            http.Error(w, err.Error(), http.StatusBadRequest)
            return
        }
    }

    // 处理mappings数组中的request
    if mappings, ok := data["mappings"].([]interface{}); ok {
        for _, item := range mappings {
            if mapping, ok := item.(map[string]interface{}); ok {
                if reqMap, ok := mapping["request"].(map[string]interface{}); ok {
                    if err := modifyReqURL(reqMap); err != nil {
                        http.Error(w, err.Error(), http.StatusBadRequest)
                        return
                    }
                }
            }
        }
    }

    // 返回修改后的JSON
    modifiedData, err := json.MarshalIndent(data, "", "    ")
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }

    w.Header().Set("Content-Type", "application/json")
    w.Write(modifiedData)
}

func main() {
    http.HandleFunc("/", handler)
    http.ListenAndServe(":8080", nil)
}

关键说明

  • 移除全局变量anytype,改用局部变量存储解析后的JSON数据,保证并发安全
  • 每次访问嵌套结构时必须做类型断言检查,避免运行时panic
  • 使用json.MarshalIndent生成格式化后的JSON,提升返回结果的可读性

内容的提问来源于stack exchange,提问作者Tom

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 07:55:02