为什么 curl POST 请求返回的结果与此 Common Library POST 请求到具有相同正文的相同地址的不同结果?
Why a curl POST request is returning a different result than this Common Library POST request to the same address with the same body?
我正在使用 Steel Bank Common Lisp (SBCL)、Emacs、Slime 和一个名为 Dexador 的库。
在REPL中,我可以做到:
CL-USER> (dex:post "https://httpbin.org/post"
:content "{\"user\": \"user1\", \"pass\":\"abcd\"}")
"{
\"args\": {},
\"data\": \"{\\"user\\": \\"user1\\", \\"pass\\": \\"abcd\\"}\",
\"files\": {},
\"form\": {},
\"headers\": {
\"Accept\": \"*/*\",
\"Content-Length\": \"33\",
\"Content-Type\": \"text/plain\",
\"Host\": \"httpbin.org\",
\"User-Agent\": \"Dexador/0.9.15 (SBCL 2.1.9.nixos); Linux; 5.10.94\",
\"X-Amzn-Trace-Id\": \"Root=1-62956dc4-1b95d37752a67b8420180f71\"
},
\"json\": {
\"pass\": \"abcd\",
\"user\": \"user1\"
},
\"origin\": \"189.2.84.243\",
\"url\": \"https://httpbin.org/post\"
}
"
删除转义字符,注意 JSON 输出的 JSON 键:
"json": {
"pass": "abcd",
"user": "user1"
}
现在,如果我在 tutorial 之后尝试在 curl 上做同样的事情,这就是我得到的:
$ curl -d "user=user1&pass=abcd" -X POST https://httpbin.org/post
{
"args": {},
"data": "",
"files": {},
"form": {
"pass": "abcd",
"user": "user1"
},
"headers": {
"Accept": "*/*",
"Content-Length": "20",
"Content-Type": "application/x-www-form-urlencoded",
"Host": "httpbin.org",
"User-Agent": "curl/7.79.1",
"X-Amzn-Trace-Id": "Root=1-62956e50-4e880d101ac23b781fe0f9d5"
},
"json": null,
"origin": "189.2.84.243",
"url": "https://httpbin.org/post"
}
注意 "json": null,
.
我原以为这两个结果是相同的,因为它们指向相同的地址并且发送的正文相同。
它们为什么不同?我错过了什么吗?
如果打开 main github repository,他将能够阅读 Usage
部分的第一个示例:
(dex:post "https://example.com/login"
:content '(("name" . "fukamachi") ("password" . "1ispa1ien")))
表单内容定义为 a-list 或 association list。关联列表在 Common Lisp 中是一个非常重要的东西,如果函数需要一个 a-list 参数,你不应该提供一个字符串:
(dex:post "https://httpbin.org/post" :content "{\"user\": \"user1\", \"pass\": \"abcd\"}")
^ this is a string not a a-list
正确的函数调用应该是:
(dex:post "https://httpbin.org/post"
:content '(("user" . "user1") ("pass" . "abcd")))
还有这个returns:
(dex:post "https://httpbin.org/post"
:content '(("user" . "user1") ("pass" . "abcd")))
#<(SIMPLE-ARRAY CHARACTER (464)) {
"args": {},
"data": "",
"files": {},
"form": { ;;
"pass": "abcd", ;; The data is here
"user": "user1" ;;
}, ;;
"headers": {
"Content-Length": "20",
"Content-Type": "application/x-www-form-urlen... {10076E5CCF}>
200
设置netcat
:
nc -l -p 3500
运行 你的 curl
命令反对:
curl -d "user=user1&pass=abcd" -X POST http://localhost:3500/post
Netcat 打印:
POST /post HTTP/1.1
Host: localhost:3500
User-Agent: curl/7.68.0
Accept: */*
Content-Length: 20
Content-Type: application/x-www-form-urlencoded
user=user1&pass=abcd
所以首先,Content-Type
是 application/x-www-form-urlencoded
,因为这就是 -d
对 curl
的意义。
其次,数据发送为user=user1&pass=abcd
,而不是JSON。那是因为 curl
的默认数据模式是 application/x-www-form-urlencoded
,它不会像你希望的那样将它发送为 JSON。
事实上,它根本没有实现 JSON。
如果你想发送 JSON,你必须明确地这样做:
jq --null-input '
.user |= "user1" |
.pass |= "abcd"' \
| curl \
-H 'Content-Type: text/plain' \
-d @- \
-X POST \
https://httpbin.org/post
回复:
{
"args": {},
"data": "{ \"user\": \"user1\", \"pass\": \"abcd\"}",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Content-Length": "36",
"Content-Type": "text/plain",
"Host": "httpbin.org",
"User-Agent": "curl/7.68.0",
"X-Amzn-Trace-Id": "Root=1-6295a78d-0d828c3c6d3891174fd22d01"
},
"json": {
"pass": "abcd",
"user": "user1"
},
"origin": "71.122.242.250",
"url": "https://httpbin.org/post"
}
我正在使用 Steel Bank Common Lisp (SBCL)、Emacs、Slime 和一个名为 Dexador 的库。
在REPL中,我可以做到:
CL-USER> (dex:post "https://httpbin.org/post"
:content "{\"user\": \"user1\", \"pass\":\"abcd\"}")
"{
\"args\": {},
\"data\": \"{\\"user\\": \\"user1\\", \\"pass\\": \\"abcd\\"}\",
\"files\": {},
\"form\": {},
\"headers\": {
\"Accept\": \"*/*\",
\"Content-Length\": \"33\",
\"Content-Type\": \"text/plain\",
\"Host\": \"httpbin.org\",
\"User-Agent\": \"Dexador/0.9.15 (SBCL 2.1.9.nixos); Linux; 5.10.94\",
\"X-Amzn-Trace-Id\": \"Root=1-62956dc4-1b95d37752a67b8420180f71\"
},
\"json\": {
\"pass\": \"abcd\",
\"user\": \"user1\"
},
\"origin\": \"189.2.84.243\",
\"url\": \"https://httpbin.org/post\"
}
"
删除转义字符,注意 JSON 输出的 JSON 键:
"json": {
"pass": "abcd",
"user": "user1"
}
现在,如果我在 tutorial 之后尝试在 curl 上做同样的事情,这就是我得到的:
$ curl -d "user=user1&pass=abcd" -X POST https://httpbin.org/post
{
"args": {},
"data": "",
"files": {},
"form": {
"pass": "abcd",
"user": "user1"
},
"headers": {
"Accept": "*/*",
"Content-Length": "20",
"Content-Type": "application/x-www-form-urlencoded",
"Host": "httpbin.org",
"User-Agent": "curl/7.79.1",
"X-Amzn-Trace-Id": "Root=1-62956e50-4e880d101ac23b781fe0f9d5"
},
"json": null,
"origin": "189.2.84.243",
"url": "https://httpbin.org/post"
}
注意 "json": null,
.
我原以为这两个结果是相同的,因为它们指向相同的地址并且发送的正文相同。
它们为什么不同?我错过了什么吗?
如果打开 main github repository,他将能够阅读 Usage
部分的第一个示例:
(dex:post "https://example.com/login"
:content '(("name" . "fukamachi") ("password" . "1ispa1ien")))
表单内容定义为 a-list 或 association list。关联列表在 Common Lisp 中是一个非常重要的东西,如果函数需要一个 a-list 参数,你不应该提供一个字符串:
(dex:post "https://httpbin.org/post" :content "{\"user\": \"user1\", \"pass\": \"abcd\"}")
^ this is a string not a a-list
正确的函数调用应该是:
(dex:post "https://httpbin.org/post"
:content '(("user" . "user1") ("pass" . "abcd")))
还有这个returns:
(dex:post "https://httpbin.org/post"
:content '(("user" . "user1") ("pass" . "abcd")))
#<(SIMPLE-ARRAY CHARACTER (464)) {
"args": {},
"data": "",
"files": {},
"form": { ;;
"pass": "abcd", ;; The data is here
"user": "user1" ;;
}, ;;
"headers": {
"Content-Length": "20",
"Content-Type": "application/x-www-form-urlen... {10076E5CCF}>
200
设置netcat
:
nc -l -p 3500
运行 你的 curl
命令反对:
curl -d "user=user1&pass=abcd" -X POST http://localhost:3500/post
Netcat 打印:
POST /post HTTP/1.1
Host: localhost:3500
User-Agent: curl/7.68.0
Accept: */*
Content-Length: 20
Content-Type: application/x-www-form-urlencoded
user=user1&pass=abcd
所以首先,Content-Type
是 application/x-www-form-urlencoded
,因为这就是 -d
对 curl
的意义。
其次,数据发送为user=user1&pass=abcd
,而不是JSON。那是因为 curl
的默认数据模式是 application/x-www-form-urlencoded
,它不会像你希望的那样将它发送为 JSON。
事实上,它根本没有实现 JSON。
如果你想发送 JSON,你必须明确地这样做:
jq --null-input '
.user |= "user1" |
.pass |= "abcd"' \
| curl \
-H 'Content-Type: text/plain' \
-d @- \
-X POST \
https://httpbin.org/post
回复:
{
"args": {},
"data": "{ \"user\": \"user1\", \"pass\": \"abcd\"}",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Content-Length": "36",
"Content-Type": "text/plain",
"Host": "httpbin.org",
"User-Agent": "curl/7.68.0",
"X-Amzn-Trace-Id": "Root=1-6295a78d-0d828c3c6d3891174fd22d01"
},
"json": {
"pass": "abcd",
"user": "user1"
},
"origin": "71.122.242.250",
"url": "https://httpbin.org/post"
}