通过 curl 发送 POST 请求时出现双引号问题

通过 curl 发送 POST 请求时出现双引号问题

因此,为了向 gists (github) 发送 POST 请求,你可以执行以下操作:https://gist.github.com/caspyi...

curl --user "user" -X POST --data '{"description":"Created via API","public":"true","files":{"file1.txt":{"content":"Demo"}}' https://api.github.com/gists

但是,在上面的例子中,文件名和文件内容是硬编码的,即部分.. file1.txt":{"content":"Demo"}..

我用我的变量替换上面的部分$file":{"content":"$content"},但初始化变量,json 请求必须用双引号括起来,我这样做了

curl --user "user" -X POST --data "{\"description\":\"Created via API\",\"public\":\"true\",\"files\":{\"$file\":{\"content\":\"$content\"}}' https://api.github.com/gists

但这不起作用,我收到 json 错误。

{
  "message": "Problems parsing JSON",
  "documentation_url": "https://developer.github.com/v3/gists/#create-a-gist"
}

即使我将所有转义的双引号替换为\'单引号。

有人知道如何在这个 json 请求中包含一个变量吗?顺便说一句:我已经使用了所有标头,例如

 -H "Content-Type: application/json; charset=UTF-8" 

并尝试了多种组合来验证请求,但都无济于事

更新。

全部内容看起来是这样的。

function gist_controller(){
    content=$(cat $1)
    DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
    read -p "enter your password - " pass 
    public="false"
    gist_content=$(cat $1)
    curl --user "samserayo"  -H "Content-Type: application/json; charset=UTF-8" -X POST -d  "{ 'description': 'Created via API', 'public': 'true', 'files':{ ' '$1 ':{ 'content': '$gist_content'}}" https://api.github.com/gists
}
更新2

导致脚本中断的文件(我尝试上传的文件是)

<?php echo 'hello world' ?>

答案1

您没有显示为 $file 或 $content 设置的值。这两个值会扩展成什么?很可能其中一个或另一个或两者都包含 JSON 解析器不喜欢的字符。最有可能的是,变量扩展值中的某些内容需要进一步转义或编码,然后才能通过 curl 提交给 JSON 解析器。

您是否已导出环境变量?

尝试:

回显“$file $content”;

以确保它们都按照您期望的方式设置。

答案2

您没有指定您使用的 shell,但双引号内的任何内容都会受到 shell 文件名扩展的影响。特别是,{} 对大多数 shell 都有意义。这就是您引用的示例使用单引号包裹整个内容的原因。

Shell 转义非常棘手,有时似乎无法得到想要的东西。老实说,在这种情况下,我会编写一个 Python 脚本来调用 curl,因为我知道 shell 不会“帮助”我。

答案3

由于这个问题被列入审核范围,所以这里还有另一个答案。

分别对各部分进行转义(关闭第一个转义,然后对变量进行转义):

curl --user "user" -X POST --data '{"description":"Created via API","public":"true","files":{"'"${file}"'":{"content":"'"${content}"'"}}}' https://api.github.com/gists

或者为了易读性而拆分:

'{"description":"Created via API","public":"true","files":{"'
"${file}"
'":{"content":"'
"${content}"
'"}}}' 

您可能需要或不需要更改内部字段分隔符,这样 shell 就不会解释变量本身中的任何空格。

梅威瑟:cat /tmp/myfile | ./thisscript.sh "myfilename.txt"

#!/bin/sh

FILENAME="${1}"
#CONTENT="$(cat)"
CONTENT="$(sed -e 's/"/\\"/g')" # escape stuff

OFS="${IFS}"
IFS=''

PERSONAL_ACCESS_TOKEN="e5fa44f2b31c1fb553b6021e7360d07d5d91ff5e"

curl --user "username:${PERSONAL_ACCESS_TOKEN}" -X POST --data '{"description":"Created via API","public":"true","files":{"'"${FILENAME}"'":{"content":"'"${CONTENT}"'"}}}' https://api.github.com/gists
IFS="${OFS}"

为了使其正常工作,你当然仍然需要转义所有会破坏 JSON 的字符,在您的文件内容中,例如"和控制字符(DOS 回车符)等。
不幸的是,他们决定使用 JSON 数据结构来文件内容上传。


如果我可以建议一种创建 Gists 的不同方法,请curl仅使用 API 调用来创建单个文件,例如README包含一些样板内容(不能为空)。
然后 grep 返回的 json 结构git_push_url克隆gist git repo。之后,您就可以直接将内容添加到 gist git commitgit push而不必担心二进制数据或转义问题。

答案4

这是一个解决方案,但它假设了两件事。

file作为第一个参数提供给脚本的文件名。 是content文件内容text

另请注意与您的不同的 POST URL(请参阅下面的解释)。

#!/bin/bash

file=$1
content=$(cat $1)

curl -H "Content-Type: application/json; charset=UTF-8" -X POST -d  "{ 'description': 'Created via API', 'public': 'true', 'files':{ ' '${file}':{ 'content': '${content}'}}" https://postman-echo.com/post

content.txt 文件包含:

This is content of the content file.

示例运行:

./curl.sh content.txt

示例输出:

{
  "args": {},
  "data": "{ 'description': 'Created via API', 'public': 'true', 'files':{ ' 'content.txt ':{ 'content': 'This is content of the content file.'}}",
  "files": {},
  "form": {},
  "headers": {
    "x-forwarded-proto": "https",
    "host": "postman-echo.com",
    "content-length": "134",
    "accept": "*/*",
    "content-type": "application/json; charset=UTF-8",
    "user-agent": "curl/7.65.3",
    "x-forwarded-port": "443"
  },
  "json": null,
  "url": "https://postman-echo.com/post"
}

笔记:

我在这里使用这个https://postman-echo.com/post网站,它会将您发布的所有内容以 JSON 格式回显。

如果 content.txt 文件的内容更复杂,此解决方案可能会失效,因为它仍必须正确转义。内容被放入“content”字段,因此 json 的所有转义规则都适用于此处。

为了看到漂亮显示的响应(如上面的 json 所示),请在 curl 末尾添加| jq .(您可能需要先安装它):

https://postman-echo.com/post | jq . 

可以使用jq自动引用整个内容文件(如果需要更高级的用法):

$ jq -Rs '.' content.txt
"This is just a text.\n"

$ jq -Rs '.' content.cpp
"#include <iostream>\nusing namespace std;\nint main() \n{\n    cout << \"Hello, World!\";\n    return 0;\n}\n"

您必须稍微修改一下脚本curl.sh才能使其正常工作:

content=$(jq -Rs '.' $1)

相关内容