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

相关推荐
郑州光合科技余经理8 分钟前
海外国际版同城服务系统开发:PHP技术栈
java·大数据·开发语言·前端·人工智能·架构·php
Yorelee.10 分钟前
ms-swift在训练时遇到的部分问题及解决方案
开发语言·nlp·transformer·swift
行走的bug...13 分钟前
python项目管理
开发语言·python
appearappear18 分钟前
Mac 上重新安装了Cursor 2.2.30,重新配置 springboot 过程记录
java·spring boot·后端
CryptoRzz27 分钟前
日本股票 API 对接实战指南(实时行情与 IPO 专题)
java·开发语言·python·区块链·maven
yugi98783828 分钟前
基于M序列的直扩信号扩频码生成方法及周期长码直扩信号的MATLAB实现方案
开发语言·matlab
谷哥的小弟34 分钟前
Spring Framework源码解析——RequestContext
java·后端·spring·框架·源码
乾元35 分钟前
基于时序数据的异常预测——短期容量与拥塞的提前感知
运维·开发语言·网络·人工智能·python·自动化·运维开发
江上清风山间明月36 分钟前
使用python将markdown文件生成pdf文件
开发语言·python·pdf
j_xxx404_39 分钟前
C++算法入门:二分查找合集(二分查找|在排序数组中查找元素的第一个和最后一个位置)
开发语言·c++