V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
Aumujun
V2EX  ›  Go 编程语言

求助, golang http post 请求问题

  •  
  •   Aumujun ·
    None · 2020-01-14 16:57:50 +08:00 · 3386 次点击
    这是一个创建于 1780 天前的主题,其中的信息可能已经有所发展或是发生改变。

    期望结果:

    • 正确获取 itop rest api 返回的工单数据

    当我使用 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 ?但我折腾了太久,直到实在没有办法才发帖求助。

    求大佬们指点,(拜谢

    12 条回复    2020-01-14 18:48:19 +08:00
    BlackBerry999
        1
    BlackBerry999  
       2020-01-14 17:24:05 +08:00
    jsonData, err := json.Marshal(request_auth)
    把这里的 jsonData 打印出来 fmt.Println(string(jsonData )) 看是否包含 [auth_user]
    Aumujun
        2
    Aumujun  
    OP
       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
        3
    virusdefender  
       2020-01-14 17:34:40 +08:00
    wireshark 抓包看下发出去的是啥样的
    BlackBerry999
        4
    BlackBerry999  
       2020-01-14 17:35:02 +08:00
    @Aumujun 我觉得是 json_data 内的字符串问题 二次 JSON 序列化 带上了很多\ 导致服务端对请求解析错误
    Aumujun
        5
    Aumujun  
    OP
       2020-01-14 18:05:05 +08:00
    @virusdefender hi,刚刚我抓包了一下,发送的值和 2 楼我发的一模一样,有可能像四楼说的那样。

    @BlackBerry999 如果是这样有什么推荐的解法吗
    useben
        6
    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
        7
    index90  
       2020-01-14 18:17:12 +08:00
    你的服务器接收的 post 请求,是 form data 格式的吧,不是 json 吧。
    r = requests.post(HOST, data=json_data)
    kidtest
        8
    kidtest  
       2020-01-14 18:19:43 +08:00
    同意楼上,post 默认的 content-type 应该是"application/x-www-form-unlencoded"
    index90
        9
    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
        10
    Vegetable  
       2020-01-14 18:20:49 +08:00
    @index90 我猜是这样,requests 的 data 参数发出去是 form,a=b&c=d 样式的,不是 json,而你 golang 的代码是用 json 发出去的
    用 url.Values 试试好了。
    kidtest
        11
    kidtest  
       2020-01-14 18:22:30 +08:00
    @kidtest
    所以,应该使用 url.Values 去存你的那些数据,然后将 Encode 之后的数据当做 body,post 出去。
    具体可以搜索:golang post form urlencoded
    Aumujun
        12
    Aumujun  
    OP
       2020-01-14 18:48:19 +08:00
    @index90
    @Vegetable
    @kidtest

    感谢几位的回复,解决了困扰我一天的难题,非常感谢。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1211 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 18:37 · PVG 02:37 · LAX 10:37 · JFK 13:37
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.