求助, golang http post 请求问题

2020-01-14 16:57:50 +08:00
 Aumujun

期望结果:

当我使用 Python 的 requests 库时,这一切都很正常,获取数据成功(如果我覆盖默认 headers,获取的结果如 golang 版本的一样。

这是 Python 的代码:

#!/usr/bin/python3
import requests, json

HOST = "http://192.168.17.22:8096/itop/webservices/rest.php?version=1.3"

json_str = json.dumps({
    "operation":
    "core/get",
    "class":
    "UserRequest",
    "key":
    "SELECT UserRequest WHERE operational_status = 'ongoing'",
    "output_fields":
    "request_type,servicesubcategory_name,urgency,origin,caller_id_friendlyname,impact,title,description",
})
json_data = {
    "auth_user": "admin",
    "auth_pwd": "goodjob@123",
    "json_data": json_str
}


# secure_rest_services
def get():
    r = requests.post(HOST, data=json_data)
    return r


if __name__ == "__main__":
    result = get()
    print(result.json())

输出

{'objects': {'UserRequest::7': {'code': 0, 'message': '', 'class': 'UserRequest', 'key': '7', 'fields': {'request_type': 'service_request', 'servicesubcategory_name': '钉钉权限开通', 'urgency': '4', 'origin': 'portal', 'caller_id_friendlyname': 'x 阿里合作项目负责人', 'impact': '1', 'title': '溫江|A-222|wb-xxxxxxxx', 'description': '<p>this is a test approve...</p>'}}, 'UserRequest::6': {'code': 0, 'message': '', 'class': 'UserRequest', 'key': '6', 'fields': {'request_type': 'service_request', 'servicesubcategory_name': '钉钉权限开通', 'urgency': '3', 'origin': 'portal', 'caller_id_friendlyname': 'x 阿里合作项目负责人', 'impact': '1', 'title': '成都|Xa-111|wb-xx111111', 'description': '<p>這是一個測試用的用戶需求</p>'}}}, 'code': 0, 'message': 'Found: 2'}

下面时 golang 版本的 post 请求

主函数:

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"strconv"
)

// 釘釘應用程序的 agentid
const (
	ITOP_URL = `http://192.168.17.22:8096/itop/webservices/rest.php?version=1.3`
)

func main() {
	request_auth := new(RequestAuth)
	request_data := new(RequestData)
	request_auth.AuthUser = "admin"
	request_auth.AuthPwd = "goodjob@123"

	request_data.Operation = "core/get"
	request_data.Class = "UserRequest"
	request_data.Key = "SELECT UserRequest WHERE operational_status = \"ongoing\""
	request_data.OutPutFields = "request_type,servicesubcategory_name,urgency,origin,caller_id_friendlyname,impact,title,description"
	req_data, err := json.Marshal(request_data)
	if err != nil {
		panic(err)
	}
	request_auth.JsonData = string(req_data)

	jsonData, err := json.Marshal(request_auth)
	if err != nil {
		panic(err)
	}
	reader := bytes.NewReader(jsonData)
	result := Post(ITOP_URL, reader)
	fmt.Println(string(result))
}

func Post(url string, reader *bytes.Reader) []byte {
	request, err := http.NewRequest("POST", url, reader)
	if err != nil {
		panic(err)
	}
	request.Header.Set("Content-Type", "application/json")
	request.Header.Set("Content-Length", strconv.Itoa(reader.Len()))
	client := http.Client{}
	resp, err := client.Do(request)
	if err != nil {
		log.Fatal(err.Error())
	}
	defer resp.Body.Close()
	respBytes, _ := ioutil.ReadAll(resp.Body)
	return respBytes
}

post 携带的数据模型

package main

// UserRequest structure
type Base struct {
	Code    int    `json:"code"`
	Message string `json:"message"`
}

type Fileds struct {
	RequestType            string `json:"request_type"`
	ServiceSubcategoryName string `json:"servicesubcategory_name"`
	Urgency                string `json:"urgency"`
	Origin                 string `json:"origin"`
	CallerIdFriendlyName   string `json:"caller_id_friendlyname"`
	Impact                 string `json:"impact"`
	Title                  string `json:"title"`
	Description            string `json:"description"`
}

type ResponseContent struct {
	Code    int    `json:"code"`
	Message string `json:"message"`
	Class   string `json:"class"`
	Key     string `json:"key"`
	Filed   Fileds `json:"fields"`
}

type Response struct {
	Base
	Object map[string]ResponseContent `json:"objects"`
}

// Request api data struct
type RequestData struct {
	Operation    string `json:"operation"`
	Class        string `json:"class"`
	Key          string `json:"key"`
	OutPutFields string `json:"output_fields"`
}

type RequestAuth struct {
	AuthUser string `json:"auth_user"`
	AuthPwd  string `json:"auth_pwd"`
	// JsonData RequestData `json:"json_data"`
	JsonData string `json:"json_data"`
}

输出:

{"code":5,"message":"Error: Missing parameter 'auth_user'"}

我猜这应该是 itop 需要 post 请求携带某个 header ?但我折腾了太久,直到实在没有办法才发帖求助。

求大佬们指点,(拜谢

3289 次点击
所在节点    Go 编程语言
12 条回复
BlackBerry999
2020-01-14 17:24:05 +08:00
jsonData, err := json.Marshal(request_auth)
把这里的 jsonData 打印出来 fmt.Println(string(jsonData )) 看是否包含 [auth_user]
Aumujun
2020-01-14 17:28:45 +08:00
@BlackBerry999

```json
{"auth_user":"admin","auth_pwd":"goodjob@123","json_data":"{\"operation\":\"core/get\",\"class\":\"UserRequest\",\"key\":\"SELECT UserRequest WHERE operational_status = \\\"ongoing\\\"\",\"output_fields\":\"request_type,servicesubcategory_name,urgency,origin,caller_id_friendlyname,impact,title,description\"}"}
```
virusdefender
2020-01-14 17:34:40 +08:00
wireshark 抓包看下发出去的是啥样的
BlackBerry999
2020-01-14 17:35:02 +08:00
@Aumujun 我觉得是 json_data 内的字符串问题 二次 JSON 序列化 带上了很多\ 导致服务端对请求解析错误
Aumujun
2020-01-14 18:05:05 +08:00
@virusdefender hi,刚刚我抓包了一下,发送的值和 2 楼我发的一模一样,有可能像四楼说的那样。

@BlackBerry999 如果是这样有什么推荐的解法吗
useben
2020-01-14 18:10:10 +08:00
type RequestData struct {
Operation string `json:"operation"`
Class string `json:"class"`
Key string `json:"key"`
OutPutFields string `json:"output_fields"`
}

type RequestAuth struct {
AuthUser string `json:"auth_user"`
AuthPwd string `json:"auth_pwd"`
// JsonData RequestData `json:"json_data"`
JsonData RequestData `json:"json_data"`
}

不需要二次序列化
index90
2020-01-14 18:17:12 +08:00
你的服务器接收的 post 请求,是 form data 格式的吧,不是 json 吧。
r = requests.post(HOST, data=json_data)
kidtest
2020-01-14 18:19:43 +08:00
同意楼上,post 默认的 content-type 应该是"application/x-www-form-unlencoded"
index90
2020-01-14 18:20:31 +08:00
py 里,如果想发送 json 数据,正确的方法是:
```
r = requests .post(HOST, data=json_dump(json_data))
```
或者
```
r = requests .post(HOST, json=json_data)
```
既然你的 py 代码能正常工作,则表明服务端把你的 post 请求,以 formdata 格式处理
Vegetable
2020-01-14 18:20:49 +08:00
@index90 我猜是这样,requests 的 data 参数发出去是 form,a=b&c=d 样式的,不是 json,而你 golang 的代码是用 json 发出去的
用 url.Values 试试好了。
kidtest
2020-01-14 18:22:30 +08:00
@kidtest
所以,应该使用 url.Values 去存你的那些数据,然后将 Encode 之后的数据当做 body,post 出去。
具体可以搜索:golang post form urlencoded
Aumujun
2020-01-14 18:48:19 +08:00
@index90
@Vegetable
@kidtest

感谢几位的回复,解决了困扰我一天的难题,非常感谢。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/637869

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX