Go开源库gcurl实际生产级应用

https://github.com/474420502/gcurl

一个在 Go 服务中安全、完整执行 curl 命令的利器

Github地址:https://github.com/474420502/gcurl

1. 为什么需要 gcurl?

先说这个业务是什么,我正在做一个服务监控系统,需要监控应用程序相关服务、服务器相关状态等,其实是有做相关后台管理页面,会展展示一些上报的数据,但是对于内部一些开发者而言,可能需要通过CLI更快的去找到相关问题,所以需要做一个支持curl相关的服务,这里就使用一个很完善的curl解析库gcurl来实现

原生 Go 的 net/http 只能手动拼 Header、Body、Method......

而用户最熟悉的表达方式就是 curl 命令

gcurl 的使命:把 99% 真实的 curl 命令完整解析并在 Go 中原生执行,包括但不限于:

curl 功能 gcurl 是否支持
-X POST/PUT/DELETE... 支持
-H "Header: value" 多条 支持
-d 'data' / --data-raw 支持
--data-binary @file 支持(v0.2.5+)
-F "key=@file.txt" 文件上传 支持
--compressed 自动解压 gzip 支持
-L 自动跳转 支持
-i 显示响应头 支持
--head / -I 只发 HEAD 支持
-u user:pass Basic Auth 支持
--insecure 跳过 TLS 验证 支持
-m 30 / --max-time 超时 支持
-x http://proxy 代理 支持
-b "cookie=1" / -c file 部分支持(v0.3+)

2. 核心用法

go 复制代码
package main

import (
    "github.com/474420502/gcurl"
    "github.com/gin-gonic/gin"
)

type Req struct {
    Cmd string `json:"cmd"`
}

func RunCurl(c *gin.Context) {
    var req Req
    if err := c.ShouldBindJSON(&req); err != nil || req.Cmd == "" {
        c.String(400, "empty cmd")
        return
    }

    // 1. 解析 curl 命令
    curlCmd, err := gcurl.Parse(req.Cmd)
    if err != nil {
        c.String(400, "parse error: %v", err)
        return
    }

    // 2. 创建会话(可复用)
    session := curlCmd.CreateSession()

    // 可选:全局超时(覆盖 -m 参数)
    session.Config().SetTimeout(60 * time.Second)

    // 3. 执行请求
    resp, err := curlCmd.CreateRequest(session).Execute()
    if err != nil {
        c.String(500, "execute error: %v", err)
        return
    }

    // 4. 判断是否需要显示 header(-i / --include / -I)
    showHeader := curlCmd.Include || curlCmd.Method == "HEAD"
    body := resp.Content()

    if showHeader {
        // 手动拼出和 curl 一模一样的响应头格式
        var buf bytes.Buffer
        fmt.Fprintf(&buf, "HTTP/%d.%d %d %s\r\n",
            resp.ProtoMajor, resp.ProtoMinor,
            resp.StatusCode, http.StatusText(resp.StatusCode))

        for k, vs := range resp.Header {
            for _, v := range vs {
                fmt.Fprintf(&buf, "%s: %s\r\n", k, v)
            }
        }
        buf.WriteString("\r\n")
        if curlCmd.Method != "HEAD" {
            buf.Write(body)
        }
        body = buf.Bytes()
    }

    // 5. 返回纯文本,和终端 curl 输出完全一致
    c.Data(200, "text/plain; charset=utf-8", body)
}

请求示例:

bash 复制代码
curl -XPOST http://localhost:8080/run -d '{"cmd":"curl -i https://httpbin.org/json"}'

返回:

复制代码
HTTP/1.1 200 OK
Content-Type: application/json
...

{"slideshow": {...}}

3. 关键 API 详解

3.1 gcurl.Parse(string) → *gcurl.CURL

解析 curl 命令,返回一个不可变的 CURL 对象。

go 复制代码
curlCmd, err := gcurl.Parse(`curl -X POST https://api.com -H "Token: 123" -d '{"a":1}'`)

3.2 curlCmd.CreateSession() → *gcurl.Session

可复用的会话,内部持有 cookie jar、自定义 Transport 等。

go 复制代码
session := curlCmd.CreateSession()
// 可以手动设置代理、跳过 TLS 等
session.Config().SetInsecureSkipVerify(true)  // 等价 --insecure
session.Config().SetProxy("http://127.0.0.1:8080")

3.3 curlCmd.CreateRequest(session) → *gcurl.Request → Execute()

真正执行请求。

go 复制代码
resp, err := curlCmd.CreateRequest(session).Execute()

resp 是标准 *http.Response 的超集:

go 复制代码
resp.StatusCode
resp.Header
resp.Content()      // []byte,已经自动解压 gzip
resp.GetResponse()  // 原生 *http.Response

4. 生产环境安全建议(非常重要)

这个功能一旦暴露到公网,等同于给黑客一个远程 curl 执行器,必须做好以下限制:

go 复制代码
// 推荐加一个白名单中间件
func CurlWhitelist() gin.HandlerFunc {
    allowHosts := map[string]bool{
        "httpbin.org": true,
        "api.github.com": true,
        // 只允许你自己的域名或测试域名
    }

    return func(c *gin.Context) {
        var req Req
        if c.ShouldBindJSON(&req) != nil {
            return
        }
        cmd, _ := gcurl.Parse(req.Cmd)
        host := strings.ToLower(cmd.URL.Host)
        if !allowHosts[host] {
            c.String(403, "host %s not allowed", host)
            c.Abort()
            return
        }
        c.Next()
    }
}

额外建议:

  • 限制最大超时 ≤ 30s
  • 限制响应体大小(gcurl 默认不限制,建议自己读 resp.Body 时 io.LimitReader)
  • 禁止本地地址(127.0.0.1、10.0.0.0/8 等)
  • 记录所有执行的 curl 命令

总结

gcurl 是目前 Go 生态里 最接近原生 curl 行为 的解析执行库,你就能在任何 Go Web 项目里实现一个「和终端 curl 输出 99% 一致」的在线执行接口。

用gcurl可以避免自己写过多的代码,来进行处理这些命令,若以上内容有错误之处,可提出,感谢观看。

相关推荐
一株菌子1 小时前
10.9总结
开发语言·python
yuuki2332331 小时前
【数据结构&C语言】排序大汇总
c语言·数据结构·后端·排序算法
间彧1 小时前
Docker 数据持久化完全指南:四种挂载方式详解与实战
后端
IT_陈寒1 小时前
SpringBoot 3.2 性能优化全攻略:7个让你的应用提速50%的关键技巧
前端·人工智能·后端
o***Z4481 小时前
Python包管理工具
开发语言·python
S***H2831 小时前
Java在微服务网关中的实现
java·开发语言·微服务
家有两宝,感恩遇见2 小时前
不能明文传证件号码后端加密解密最简单的方式AES
java·服务器·开发语言
爱学习的小邓同学2 小时前
C++ --- 继承
开发语言·c++
❀͜͡傀儡师2 小时前
springboot集成mqtt服务,自主下发
java·spring boot·后端·mqtt·netty