【发布时间】:2015-06-08 07:01:33
【问题描述】:
我可以使用 POSTMAN chrome 扩展对字符串数据进行 POST 请求。
我需要使用golang 代码来做同样的事情。
但是我的Go 代码丢失了字符串INSERT INTO V SET name = 'jack', boss = #11:19 并将空数据发布到服务器。
package main
import (
"bytes"
"encoding/json"
"fmt"
"log"
"net/http"
)
func main() {
client := &http.Client{}
// Why this stringData is lost and was not send with POST request?
stringData := `INSERT INTO V SET name = 'jack', boss = #11:19`
req, err := http.NewRequest("POST", "http://localhost:2480/command/GratefulDeadConcerts/sql", bytes.NewBufferString(stringData))
req.SetBasicAuth("root", "1")
resp, err := client.Do(req)
if err != nil {
fmt.Printf("Error : %s", err)
}
fmt.Println("resp")
fmt.Println(ToJson(resp))
var b bytes.Buffer
_, err = b.ReadFrom(resp.Body)
if err != nil {
log.Fatal("Error : %s", err)
}
fmt.Println(b.String())
}
func ToJson(obj interface{}) string {
b, err := json.MarshalIndent(&obj, "", " ")
if err != nil {
fmt.Printf("Error : %s", err)
}
strJson := string(b)
return strJson
}
它给出输出:
resp
{
"Status": "500 Internal Server Error",
"StatusCode": 500,
"Proto": "HTTP/1.1",
"ProtoMajor": 1,
"ProtoMinor": 1,
"Header": {
"Cache-Control": [
"no-cache, no-store, max-age=0, must-revalidate"
],
"Connection": [
"Keep-Alive"
],
"Content-Length": [
"55"
],
"Content-Type": [
"text/plain; charset=utf-8"
],
"Date": [
"Mon Jun 08 10:47:46 MSK 2015"
],
"Pragma": [
"no-cache"
],
"Server": [
"OrientDB Server v.2.0.10 (build UNKNOWN@r; 2015-05-25 16:48:43+0000)"
]
},
"Body": {},
"ContentLength": 55,
"TransferEncoding": null,
"Close": false,
"Trailer": null,
"Request": {
"Method": "POST",
"URL": {
"Scheme": "http",
"Opaque": "",
"User": null,
"Host": "localhost:2480",
"Path": "/command/GratefulDeadConcerts/sql",
"RawQuery": "",
"Fragment": ""
},
"Proto": "HTTP/1.1",
"ProtoMajor": 1,
"ProtoMinor": 1,
"Header": {
"Authorization": [
"Basic cm9vdDox"
]
},
"Body": {
"Reader": {}
},
"ContentLength": 46,
"TransferEncoding": null,
"Close": false,
"Host": "localhost:2480",
"Form": null,
"PostForm": null,
"MultipartForm": null,
"Trailer": null,
"RemoteAddr": "",
"RequestURI": "",
"TLS": null
},
"TLS": null
}
java.lang.IllegalArgumentException: text cannot be null
如何使用 GoLang 使这个 POST 请求成功运行,就像我可以使用 POSTMAN chrome 扩展一样?
更新
我使用 curl 成功发出了相同的 POST 请求。
curl -X POST -u root:1 -H "Content-Type: application/json" --data-urlencode "INSERT INTO V SET name = 'jack', boss = #11:19" http://localhost:2480/command/GratefulDeadConcerts/sql
它输出:
{"result":[{"@type":"d","@rid":"#9:822","@version":1,"@class":"V","name":null}]}
更新 2
当然,我不应该将--data-urlencode 用于curl 命令。
有效的 curl 命令是
curl -X POST -u root:1 -H "Content-Type: application/json" -d "INSERT INTO V SET name = 'jack', boss = #11:19" http://localhost:2480/command/GratefulDeadConcerts/sql
{"result":[{"@type":"d","@rid":"#9:848","@version":1,"@class":"V","name":"jack","boss":"#11:19","@fieldTypes":"boss=x"}]}
我仍然不知道如何发出类似的 GoLang POST 请求。
更新 3
url.QueryEscape 没有帮助我。
package main
import (
"bytes"
"encoding/json"
"fmt"
"log"
"net/http"
"net/url"
)
func main() {
client := &http.Client{}
// Why this stringData is lost and do not pass thgouht POST request?
stringData := `INSERT INTO V SET name = 'jack', boss = #11:19`
stringData = url.QueryEscape(stringData)
req, err := http.NewRequest("POST", "http://localhost:2480/command/GratefulDeadConcerts/sql", bytes.NewBufferString(stringData))
req.SetBasicAuth("root", "1")
req.Header.Set("Content-Type", "Content-Type: text/plain")
resp, err := client.Do(req)
if err != nil {
fmt.Printf("Error : %s", err)
}
fmt.Println("resp")
fmt.Println(ToJson(resp))
var b bytes.Buffer
_, err = b.ReadFrom(resp.Body)
if err != nil {
log.Fatal("Error : %s", err)
}
fmt.Println(b.String())
}
func ToJson(obj interface{}) string {
b, err := json.MarshalIndent(&obj, "", " ")
if err != nil {
fmt.Printf("Error : %s", err)
}
strJson := string(b)
return strJson
}
结果是一样的:
resp
{
"Status": "500 Internal Server Error",
"StatusCode": 500,
"Proto": "HTTP/1.1",
"ProtoMajor": 1,
"ProtoMinor": 1,
"Header": {
"Cache-Control": [
"no-cache, no-store, max-age=0, must-revalidate"
],
"Connection": [
"Keep-Alive"
],
"Content-Length": [
"55"
],
"Content-Type": [
"text/plain; charset=utf-8"
],
"Date": [
"Mon Jun 08 19:39:12 MSK 2015"
],
"Pragma": [
"no-cache"
],
"Server": [
"OrientDB Server v.2.0.10 (build UNKNOWN@r; 2015-05-25 16:48:43+0000)"
]
},
"Body": {},
"ContentLength": 55,
"TransferEncoding": null,
"Close": false,
"Trailer": null,
"Request": {
"Method": "POST",
"URL": {
"Scheme": "http",
"Opaque": "",
"User": null,
"Host": "localhost:2480",
"Path": "/command/GratefulDeadConcerts/sql",
"RawQuery": "",
"Fragment": ""
},
"Proto": "HTTP/1.1",
"ProtoMajor": 1,
"ProtoMinor": 1,
"Header": {
"Authorization": [
"Basic cm9vdDox"
],
"Content-Type": [
"Content-Type: text/plain"
]
},
"Body": {
"Reader": {}
},
"ContentLength": 60,
"TransferEncoding": null,
"Close": false,
"Host": "localhost:2480",
"Form": null,
"PostForm": null,
"MultipartForm": null,
"Trailer": null,
"RemoteAddr": "",
"RequestURI": "",
"TLS": null
},
"TLS": null
}
java.lang.IllegalArgumentException: text cannot be null
另外,我在curl 命令中将内容类型更改为text/plain。
curl -X POST -u root:1 -H "Content-Type: text/plain" -d "INSERT INTO V SET name = 'jack', boss = #11:19" http://localhost:2480/command/GratefulDeadConcerts/sql
{"result":[{"@type":"d","@rid":"#9:858","@version":1,"@class":"V","name":"jack","boss":"#11:19","@fieldTypes":"boss=x"}]}
结果是一样的,curl 可以,但golang POST 不行。
更新 4
我想做什么?我正在实现 OrientDB REST-interface 以执行来自 GO 应用程序的查询。
【问题讨论】:
-
只是好奇:由
bytes.NewBufferString创建的bytes.Buffer是否实现io.Reader? -
第一:是什么让你觉得 Go 发送的请求体是空的?它不是。第二:您的 Java 服务器明确指出需要非空“文本”,也许您应该提供一个。第三:使用 curl,而不是 postman。邮递员很好,但 curl 清楚地说明了实际发生的情况。
-
为什么使用 curl 以 URL 编码形式发送此 SQL 语句,而使用 Go 以纯字符串形式发送? @thecoshman 提出了一个非常有效的观点:为什么将我们的 Content-type 设置为 JSON,但发送 URL 编码的数据?在尝试在 Go 中进行之前,您可能想更深入地了解 HTTP 的工作原理并研究 Java 服务器的 API 端点的文档。试错编程没有帮助。
-
只需对你的身体进行 URL 编码,因为 curl 会自动为你进行编码(参见 golang.org/pkg/net/url/#QueryEscape)。请注意,您的 curl 调用仍然是错误的:您的内容类型不是 JSON。还有一个:您可以发布(或链接)到您的 API 端点规范/描述,而不是发布 curl 或邮递员示例。
-
作为旁注:我不知道您究竟想在这里做什么,但是将原始 sql 语句作为帖子正文发送会使我的眼睛喷出,我的手指抽搐。我只能希望您实际上并没有这样做(即使在内部网络中),因为从安全角度来看,这非常非常糟糕。只需发送一个带有数据的 json/xml/postparam blob 并解析和 validate 该服务器端,然后才能从中创建一个 sql 语句。像这样,您想知道是谁制作了所有这些新表以及用户表中的用户“乔”是谁只是时间问题。