PHP与Golang的HTTP调用会得到不同的结果

huangapple go评论125阅读模式
英文:

PHP vs Golang http calls gets different results

问题

我正在尝试在Google App Engine Go中实现以下PHP代码:

  1. <?php
  2. function api_query(array $req = array()) {
  3. $key = '90294318da0162b082c3d27126be80c3873955f9';
  4. $req['method'] = 'getinfo';
  5. $req['nonce'] = 1394503747386411;
  6. // 生成POST数据字符串
  7. $post_data = http_build_query($req, '', '&');
  8. $sign = '75da1e3ff750286bf73d03197f1b779fbfff963fd7402941ae326509a6615eacb839b44f236b4d5ee6cff39321e7b35e9563a9a2075e99df0f4ee3b732999348';
  9. // 生成额外的头部信息
  10. $headers = array(
  11. 'Sign: '.$sign,
  12. 'Key: '.$key,
  13. );
  14. // 初始化curl句柄
  15. static $ch = null;
  16. if (is_null($ch)) {
  17. $ch = curl_init();
  18. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  19. curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; Cryptsy API PHP client; '.php_uname('s').'; PHP/'.phpversion().')');
  20. }
  21. curl_setopt($ch, CURLOPT_URL, 'https://api.cryptsy.com/api');
  22. curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
  23. curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
  24. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
  25. // 执行查询
  26. $res = curl_exec($ch);
  27. if ($res === false) throw new Exception('Could not get reply: '.curl_error($ch));
  28. $dec = json_decode($res, true);
  29. if (!$dec) throw new Exception('Invalid data received, please make sure connection is working and requested API exists');
  30. echo "<pre>".print_r($dec, true)."</pre>";
  31. return $dec;
  32. }
  33. api_query();

执行该代码后,会返回一个JSON数组。我尝试在Golang中实现相同的代码:

  1. func PrivateCall(c appengine.Context) (map[string]interface{}, error) {
  2. AuthAPI := "https://api.cryptsy.com/api"
  3. APIKey := "90294318da0162b082c3d27126be80c3873955f9"
  4. tr := urlfetch.Transport{Context: c}
  5. values := url.Values{}
  6. values.Set("method", "getinfo")
  7. values.Set("nonce", "1394503747386411")
  8. signature := "75da1e3ff750286bf73d03197f1b779fbfff963fd7402941ae326509a6615eacb839b44f236b4d5ee6cff39321e7b35e9563a9a2075e99df0f4ee3b732999348"
  9. req, err := http.NewRequest("POST", AuthAPI+"?"+values.Encode(), nil)
  10. if err != nil {
  11. c.Infof("API - Call - error 2 - %s", err.Error())
  12. return nil, err
  13. }
  14. req.Header.Set("Key", APIKey)
  15. req.Header.Set("Sign", signature)
  16. c.Infof("req - %v", req)
  17. resp, err := tr.RoundTrip(req)
  18. if err != nil {
  19. c.Errorf("API post error: %s", err)
  20. return nil, err
  21. }
  22. defer resp.Body.Close()
  23. // 读取响应
  24. body, err := ioutil.ReadAll(resp.Body)
  25. if err != nil {
  26. c.Errorf("API read error: could not read body: %s", err)
  27. return nil, err
  28. }
  29. result := make(map[string]interface{})
  30. // 解析JSON响应
  31. err = json.Unmarshal(body, &result)
  32. if err != nil {
  33. c.Infof("Unmarshal: %v", err)
  34. c.Infof("%s", body)
  35. return nil, err
  36. }
  37. return result, nil
  38. }

我收到一个错误消息,提示"无法授权请求-请检查您的POST数据"。有人能看出可能导致这个错误的原因吗?目前我最好的猜测是Go中的请求头是map[string][]string,而PHP中似乎是一个数组...

英文:

I am trying to implement the following PHP code in Google App Engine Go:

  1. &lt;?php
  2. function api_query(array $req = array()) {
  3. $key = &#39;90294318da0162b082c3d27126be80c3873955f9&#39;;
  4. $req[&#39;method&#39;] = &#39;getinfo&#39;;
  5. $req[&#39;nonce&#39;] = 1394503747386411;
  6. // generate the POST data string
  7. $post_data = http_build_query($req, &#39;&#39;, &#39;&amp;&#39;);
  8. $sign = &#39;75da1e3ff750286bf73d03197f1b779fbfff963fd7402941ae326509a6615eacb839b44f236b4d5ee6cff39321e7b35e9563a9a2075e99df0f4ee3b732999348&#39;;
  9. // generate the extra headers
  10. $headers = array(
  11. &#39;Sign: &#39;.$sign,
  12. &#39;Key: &#39;.$key,
  13. );
  14. // our curl handle (initialize if required)
  15. static $ch = null;
  16. if (is_null($ch)) {
  17. $ch = curl_init();
  18. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  19. curl_setopt($ch, CURLOPT_USERAGENT, &#39;Mozilla/4.0 (compatible; Cryptsy API PHP client; &#39;.php_uname(&#39;s&#39;).&#39;; PHP/&#39;.phpversion().&#39;)&#39;);
  20. }
  21. curl_setopt($ch, CURLOPT_URL, &#39;https://api.cryptsy.com/api&#39;);
  22. curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data);
  23. curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
  24. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
  25. // run the query
  26. $res = curl_exec($ch);
  27. if ($res === false) throw new Exception(&#39;Could not get reply: &#39;.curl_error($ch));
  28. $dec = json_decode($res, true);
  29. if (!$dec) throw new Exception(&#39;Invalid data received, please make sure connection is working and requested API exists&#39;);
  30. echo &quot;&lt;pre&gt;&quot;.print_r($dec, true).&quot;&lt;/pre&gt;&quot;;
  31. return $dec;
  32. }
  33. api_query();

When executed, the code returns a JSON array of values. I tried implementing the same code in Golang:

  1. func PrivateCall(c appengine.Context) (map[string]interface{}, error) {
  2. AuthAPI := &quot;https://api.cryptsy.com/api&quot;
  3. APIKey := &quot;90294318da0162b082c3d27126be80c3873955f9&quot;
  4. tr := urlfetch.Transport{Context: c}
  5. values := url.Values{}
  6. values.Set(&quot;method&quot;, &quot;getinfo&quot;)
  7. values.Set(&quot;nonce&quot;, &quot;1394503747386411&quot;)
  8. signature := &quot;75da1e3ff750286bf73d03197f1b779fbfff963fd7402941ae326509a6615eacb839b44f236b4d5ee6cff39321e7b35e9563a9a2075e99df0f4ee3b732999348&quot;
  9. req, err := http.NewRequest(&quot;POST&quot;, AuthAPI+&quot;?&quot;+values.Encode(), nil)
  10. if err != nil {
  11. c.Infof(&quot;API - Call - error 2 - %s&quot;, err.Error())
  12. return nil, err
  13. }
  14. req.Header.Set(&quot;Key&quot;, APIKey)
  15. req.Header.Set(&quot;Sign&quot;, signature)
  16. c.Infof(&quot;req - %v&quot;, req)
  17. resp, err := tr.RoundTrip(req)
  18. if err != nil {
  19. c.Errorf(&quot;API post error: %s&quot;, err)
  20. return nil, err
  21. }
  22. defer resp.Body.Close()
  23. //reading response
  24. body, err := ioutil.ReadAll(resp.Body)
  25. if err != nil {
  26. c.Errorf(&quot;API read error: could not read body: %s&quot;, err)
  27. return nil, err
  28. }
  29. result := make(map[string]interface{})
  30. //unmarshalling JSON response
  31. err = json.Unmarshal(body, &amp;result)
  32. if err != nil {
  33. c.Infof(&quot;Unmarshal: %v&quot;, err)
  34. c.Infof(&quot;%s&quot;, body)
  35. return nil, err
  36. }
  37. return result, nil
  38. }

I am getting an error saying "Unable to Authorize Request - Check Your Post Data". Does anyone see what could've caused this error? At the moment my best guess is that perhaps the request header in Go is a map[string][]string, while in PHP it appears to be an array...

答案1

得分: 3

根据LeGEC的建议,你将POST数据放在URL的末尾,就像是一个GET请求。

尝试将以下代码替换为:

  1. data := struct {
  2. method string
  3. nonce string
  4. }{
  5. "getinfo",
  6. "1394503747386411",
  7. }
  8. signature := "75da1e3ff750286bf73d03197f1b779fbfff963fd7402941ae326509a6615eacb839b44f236b4d5ee6cff39321e7b35e9563a9a2075e99df0f4ee3b732999348"
  9. postData, err := json.Marshal(data)
  10. if err != nil {
  11. return nil, err
  12. }
  13. buf := bytes.NewBuffer(postData)
  14. req, err := http.Post(AuthAPI, "application/json", buf)

这样做可以将数据作为JSON格式的请求体发送。

英文:

As suggested by LeGEC, you're putting the POST data onto the end of the URL as if it were a GET request.

Try replacing

  1. values := url.Values{}
  2. values.Set(&quot;method&quot;, &quot;getinfo&quot;)
  3. values.Set(&quot;nonce&quot;, &quot;1394503747386411&quot;)
  4. signature := &quot;75da1e3ff750286bf73d03197f1b779fbfff963fd7402941ae326509a6615eacb839b44f236b4d5ee6cff39321e7b35e9563a9a2075e99df0f4ee3b732999348&quot;
  5. req, err := http.NewRequest(&quot;POST&quot;, AuthAPI+&quot;?&quot;+values.Encode(), nil)

with

  1. data := struct {
  2. method string
  3. nonce string
  4. }{
  5. &quot;getinfo&quot;,
  6. &quot;1394503747386411&quot;,
  7. }
  8. signature := &quot;75da1e3ff750286bf73d03197f1b779fbfff963fd7402941ae326509a6615eacb839b44f236b4d5ee6cff39321e7b35e9563a9a2075e99df0f4ee3b732999348&quot;
  9. postData, err := json.Marshal(data)
  10. if err != nil {
  11. return nil, err
  12. }
  13. buf := bytes.NewBuffer(postData)
  14. req, err := http.Post(AuthAPI, &quot;application/json&quot;, buf)

答案2

得分: 1

data := map[string]interface{}{
"int": 1,
"str": "str",
"arr_int": []int16{1, -2, 4},
"m_arr": map[string][]int16{
"test": []int16{1, -2, 4},
},
"m_m": []interface{}{
map[string]string{"mo1": "v", "mo2": "v2"},
map[string]string{"mo2": "v"},
},
"m_m_m": map[string]interface{}{
"mm": struct{ Name string }{"张三"},
},
}
str := Encode(data)

// 输出结果
// int=1&str=str&arr_int[]=1&arr_int[]=-2&arr_int[]=4&m_arr[test][0]=1&m_arr[test][1]=-2&m_arr[test][2]=4&m_m[0][mo1]=v&m_m[0][mo2]=v2&m_m[1][mo2]=v&m_m_m[mm][Name]=张三

英文:

https://github.com/ctfang/http_build_query

  1. data := map[string]interface{}{
  2. &quot;int&quot;: 1,
  3. &quot;str&quot;: &quot;str&quot;,
  4. &quot;arr_int&quot;: []int16{1, -2, 4},
  5. &quot;m_arr&quot;: map[string][]int16{
  6. &quot;test&quot;: []int16{1, -2, 4},
  7. },
  8. &quot;m_m&quot;: []interface{}{
  9. map[string]string{&quot;mo1&quot;: &quot;v&quot;, &quot;mo2&quot;: &quot;v2&quot;},
  10. map[string]string{&quot;mo2&quot;: &quot;v&quot;},
  11. },
  12. &quot;m_m_m&quot;: map[string]interface{}{
  13. &quot;mm&quot;: struct{ Name string }{&quot;张三&quot;},
  14. },
  15. }
  16. str := Encode(data)
  17. // echo
  18. // int=1&amp;str=str&amp;arr_int[]=1&amp;arr_int[]=-2&amp;arr_int[]=4&amp;m_arr[test][0]=1&amp;m_arr[test][1]=-2&amp;m_arr[test][2]=4&amp;m_m[0][mo1]=v&amp;m_m[0][mo2]=v2&amp;m_m[1][mo2]=v&amp;m_m_m[mm][Name]=张三

答案3

得分: 0

这是你需要的内容,以及你错过的几个要点。

  • 在使用https时,需要设置TLSClientConfig
  • 自定义头部缺少X-前缀。
  • values.Encode()的位置错误。

示例:请参考 https://www.cryptsy.com/pages/api

  1. var (
  2. urlStr = "https://api.cryptsy.com/api"
  3. key = "YOUR KEY"
  4. secret = "YOUR SECRECT"
  5. agent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.146 Safari/537.36"
  6. )
  7. func main() {
  8. client := &http.Client{Transport: &http.Transport{
  9. TLSClientConfig: &tls.Config{
  10. InsecureSkipVerify: true,
  11. },
  12. }}
  13. values := url.Values{}
  14. // $req['method'] = $method;
  15. values.Set("method", "getinfo")
  16. // $mt = explode(' ', microtime());
  17. // $req['nonce'] = $mt[1];
  18. values.Set("nonce", time.Nanosecond.String())
  19. // $post_data = http_build_query($req, '', '&');
  20. encoded := values.Encode()
  21. mac := hmac.New(sha512.New, []byte(secret))
  22. mac.Write([]byte(encoded))
  23. //$sign = hash_hmac("sha512", $post_data, $secret);
  24. sign := fmt.Sprintf("%x", mac.Sum(nil))
  25. req, err := http.NewRequest("POST", urlStr, bytes.NewBufferString(encoded))
  26. if err != nil {
  27. log.Fatalln(err)
  28. }
  29. // generate the extra headers
  30. // $headers = array(
  31. // 'Sign: '.$sign,
  32. // 'Key: '.$key,
  33. // );
  34. req.Header.Set("X-Sign", sign)
  35. req.Header.Set("X-Key", key)
  36. // curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; Cryptsy API PHP client; '.php_uname('s').'; PHP/'.phpversion().')');
  37. req.Header.Set("User-Agent", agent)
  38. req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
  39. req.Header.Add("Content-Length", strconv.Itoa(len(encoded)))
  40. // $res = curl_exec($ch);
  41. resp, err := client.Do(req)
  42. if err != nil {
  43. log.Fatalln(err)
  44. }
  45. fmt.Println(resp.Status)
  46. data, _ := ioutil.ReadAll(resp.Body)
  47. fmt.Printf("%s", data)
  48. }
英文:

Here is what you need and here are the few things you missed.

  • When working with https you need to set the TLSClientConfig
  • Missing X- prefix in custom headers
  • values.Encode() is the the wrong position.

Example: See https://www.cryptsy.com/pages/api

  1. var (
  2. urlStr = &quot;https://api.cryptsy.com/api&quot;
  3. key = &quot;YOUR KEY&quot;
  4. secret = &quot;YOUR SECRECT&quot;
  5. agent = &quot;Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.146 Safari/537.36&quot;
  6. )
  7. func main() {
  8. client := &amp;http.Client{Transport: &amp;http.Transport{
  9. TLSClientConfig: &amp;tls.Config{
  10. InsecureSkipVerify: true,
  11. },
  12. }}
  13. values := url.Values{}
  14. // $req[&#39;method&#39;] = $method;
  15. values.Set(&quot;method&quot;, &quot;getinfo&quot;)
  16. // $mt = explode(&#39; &#39;, microtime());
  17. // $req[&#39;nonce&#39;] = $mt[1];
  18. values.Set(&quot;nonce&quot;, time.Nanosecond.String())
  19. // $post_data = http_build_query($req, &#39;&#39;, &#39;&amp;&#39;);
  20. encoded := values.Encode()
  21. mac := hmac.New(sha512.New, []byte(secret))
  22. mac.Write([]byte(encoded))
  23. //$sign = hash_hmac(&quot;sha512&quot;, $post_data, $secret);
  24. sign := fmt.Sprintf(&quot;%x&quot;, mac.Sum(nil))
  25. req, err := http.NewRequest(&quot;POST&quot;, urlStr, bytes.NewBufferString(encoded))
  26. if err != nil {
  27. log.Fatalln(err)
  28. }
  29. // generate the extra headers
  30. // $headers = array(
  31. // &#39;Sign: &#39;.$sign,
  32. // &#39;Key: &#39;.$key,
  33. // );
  34. req.Header.Set(&quot;X-Sign&quot;, sign)
  35. req.Header.Set(&quot;X-Key&quot;, key)
  36. // curl_setopt($ch, CURLOPT_USERAGENT, &#39;Mozilla/4.0 (compatible; Cryptsy API PHP client; &#39;.php_uname(&#39;s&#39;).&#39;; PHP/&#39;.phpversion().&#39;)&#39;);
  37. req.Header.Set(&quot;User-Agent&quot;, agent)
  38. req.Header.Add(&quot;Content-Type&quot;, &quot;application/x-www-form-urlencoded&quot;)
  39. req.Header.Add(&quot;Content-Length&quot;, strconv.Itoa(len(encoded)))
  40. // $res = curl_exec($ch);
  41. resp, err := client.Do(req)
  42. if err != nil {
  43. log.Fatalln(err)
  44. }
  45. fmt.Println(resp.Status)
  46. data, _ := ioutil.ReadAll(resp.Body)
  47. fmt.Printf(&quot;%s&quot;, data)
  48. }

huangapple
  • 本文由 发表于 2014年3月11日 10:37:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/22315378.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定