【问题标题】:POST golang request with string data带有字符串数据的 POST golang 请求
【发布时间】: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 语句。像这样,您想知道是谁制作了所有这些新表以及用户表中的用户“乔”是谁只是时间问题。

标签: rest go


【解决方案1】:

阅读文档会有所帮助。来自 OrientDB 文档文档 [1]:

所有请求都必须有这两个标头:

'Accept-Encoding': 'gzip,deflate'
'Content-Length': <content-length>

其中 是请求正文的长度。

而且您没有设置 Accept-Encoding 标头。很可能这就是你所需要的(而不是逃避身体)。

[1]http://orientdb.com/docs/last/orientdb.wiki/OrientDB-REST.html#headers

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-01
    • 1970-01-01
    • 2018-05-07
    • 2016-07-09
    • 2013-02-26
    • 1970-01-01
    相关资源
    最近更新 更多