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可以避免自己写过多的代码,来进行处理这些命令,若以上内容有错误之处,可提出,感谢观看。

相关推荐
星火开发设计4 分钟前
类型别名 typedef:让复杂类型更简洁
开发语言·c++·学习·算法·函数·知识
qq_1777673716 分钟前
React Native鸿蒙跨平台数据使用监控应用技术,通过setInterval每5秒更新一次数据使用情况和套餐使用情况,模拟了真实应用中的数据监控场景
开发语言·前端·javascript·react native·react.js·ecmascript·harmonyos
一匹电信狗18 分钟前
【LeetCode_21】合并两个有序链表
c语言·开发语言·数据结构·c++·算法·leetcode·stl
2401_8384725144 分钟前
C++中的访问者模式
开发语言·c++·算法
csbysj20201 小时前
《Foundation 开关:深度解析其原理与应用》
开发语言
怪兽源码1 小时前
基于SpringBoot的选课调查系统
java·spring boot·后端·选课调查系统
梦里小白龙1 小时前
java 通过Minio上传文件
java·开发语言
m0_561359671 小时前
基于C++的机器学习库开发
开发语言·c++·算法
星空露珠2 小时前
速算24点所有题库公式
开发语言·数据库·算法·游戏·lua
csdn_aspnet2 小时前
ASP.NET Core 中的依赖注入
后端·asp.net·di·.net core