如何在Golang中执行需要上传文件的cURL请求?

发布于 2025-01-11 12:18:34 字数 620 浏览 0 评论 0原文

我有一个 cURL 请求,如下所示。

$(curl --request PUT --upload-file "<path to catalog file on your local machine>" "<presigned URL>")

假设我必须上传一个 bin/test.txt 文件,其 presigned URLhttps://www.someurl.com

我在我的终端中执行命令 curl --request PUT --upload-file "bin/test.txt" "https://www.someurl.com" 它工作正常。

我如何编写一段具有相同功能的 Golang 代码?我尝试过

cmd := exec.Command("curl", "--request", "PUT", "--upload-file", fmt.Sprintf("\"%s\"", catalogPath), fmt.Sprintf("\"%s\"", presignedURL))
err = cmd.Run()

但没有成功。

I have a cURL request as follows.

$(curl --request PUT --upload-file "<path to catalog file on your local machine>" "<presigned URL>")

Let's say that I have to upload a bin/test.txt file with the presigned URL being https://www.someurl.com

I execute the command in my terminal
curl --request PUT --upload-file "bin/test.txt" "https://www.someurl.com" and it works fine.

How do I write a piece of Golang which does the same? I have tried

cmd := exec.Command("curl", "--request", "PUT", "--upload-file", fmt.Sprintf("\"%s\"", catalogPath), fmt.Sprintf("\"%s\"", presignedURL))
err = cmd.Run()

but found no success.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

放低过去 2025-01-18 12:18:34

我发现一个明显的问题导致 curl 调用无法正常工作,一个很可能,另一个也可能。

明显的问题是字符串引用——例如执行curl … --upload-file "bin/test.txt" …——由执行命令的shell解释。引号(使用双引号或单引号)用于禁止 shell 解释其他特殊字符;主要用于防止 shell 将字符串拆分为空白字符或其系列上的单独“单词”。
关键要点是,在完全解析要执行的命令(并解释引号)后,shell 运行的命令不会“看到”这些引号,因为它们已被 shell 删除。

os/exec.Cmd 直接调用指定的程序,而不是“通过”shell “传递它”。因此,如果您在要执行的程序的命令行参数中包含双引号,它们就会原封不动地传递给该程序。这意味着,curl 将尝试在名为 "bin 的目录中查找名为 test.txt" 的文件 - 这很可能不是你所期望的。
这同样适用于 URL。

第二个可能的问题是您的调用依赖于 Go 程序的当前目录,因为您将相对路径传递给 curl
这可能是问题,也可能不是问题,但无论如何您都可以检查一下。

第三个问题是,您可能希望通过“百分比转义”算法传递 URL 在将其传递给 curl 之前。
您可以查看 PathEscapeQueryEscape 函数net/url


以下是两条建议。

首先,我会非常努力地不调用 curl 来执行如此简单的任务。 Go 在其标准库中对发出 HTTP 请求(并为它们提供服务,FWIW)提供了出色的支持,并且 PUT 操作确实是轻而易举的事,只需五分钟就可以通过谷歌搜索到解决方案。

其次,如果出于某种原因,您打算坚持调用curl,请考虑向它传递一些选项,使其在错误时大声失败 - 否则您注定会陷入“但没有成功”的境地”你尝试中的情况。例如,考虑将 -s-S 命令行选项(一起)传递给 curl

I see one obvious problem preventing that curl call from working properly, one quite possible and another one also possible.

The obvious problem is that string quoting — such as executing curl … --upload-file "bin/test.txt" … — in interpreted by the shell which is to execute the command. Quoting — using either double or single quotes — is used to inhibit interpreting of otherwise special characters by the shell; chiefly it's used to prevent the shell from splitting a string into separate "words" on whitespace characters or their series.
The key takeaway is that the command run by the shell after it's fully parsed the command to be executed (and interpreted the quotes) does not "see" these quotes because they are removed by the shell.

os/exec.Cmd calls the specified program directly and does not "pass it through" the shell. Hence if you include double quotes into the command-line parameters of the program to execute, they are passed to that program, unchanged. This means, curl were to try to find the file named test.txt" located in the directory named "bin — which is most probably not what you expected.
The same applied to the URL.

The second — possible — problem is that your call relies on the current directory of your Go program because you pass a relative path to curl.
This might or might not be a problem but you might check this anyway.

The third problem is that you might want to pass your URL through the "percent escaping" algorithm before passing it to curl.
You might look at PathEscape and QueryEscape functions of the net/url package.


Two pieces of advice follow.

First, I would try very hard not to call out to curl to perform such a ridiculously simple task. Go has excellent support for making HTTP requests (and serving them, FWIW) in its standard library, and PUTting a file is really a no-brainer with a solutions googleable in, like, five minutes.

Second, if, for some reason, you intend to stick with calling curl, consider passing it some options to make it fail loudly on errors — otherwise you're doomed to be in that „but found no success” situation in your attempts. For instance, consider passing curl the -s and -S command line options (together).

删除→记忆 2025-01-18 12:18:34

这不是你引用 shell 参数的方式,如果你的参数以 \" 开头或结尾,那么就会中断,在 unix 上引用 shell 参数的正确方法是

func quoteshellarg(str string) string {
    if strings.Contains(str, "\x00") {
        panic("argument contains null bytes, it is impossible to escape null bytes in shell arguments!")
    }
    return "'" + strings.ReplaceAll(str, "'", "'\\''") + "'"
}

和那,只是

cmd := exec.Command("curl --request PUT --upload-file " + quoteshellarg(catalogPath)+ " " + quoteshellarg(presignedURL));

……至少在unix系统上是这样,至于在Windows上如何做,似乎没有人确切知道,甚至微软也没有

that's not how you quote shell arguments, that would break if your argument starts with or ends with \ or ", the proper way to quote shell arguments on unix would be

func quoteshellarg(str string) string {
    if strings.Contains(str, "\x00") {
        panic("argument contains null bytes, it is impossible to escape null bytes in shell arguments!")
    }
    return "'" + strings.ReplaceAll(str, "'", "'\\''") + "'"
}

and with that, just

cmd := exec.Command("curl --request PUT --upload-file " + quoteshellarg(catalogPath)+ " " + quoteshellarg(presignedURL));

... at least that's how to do it on unix systems. as for how to do it on Windows, it seems nobody knows for sure, not even Microsoft

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文