2014-03-11 1 views
-1

Я пытаюсь выполнить следующий PHP код в Google App Engine Перейти:PHP против Golang HTTP вызовов получает различные результаты

<?php 

function api_query(array $req = array()) { 
     $key = '90294318da0162b082c3d27126be80c3873955f9'; 

     $req['method'] = 'getinfo'; 
     $req['nonce'] = 1394503747386411; 

     // generate the POST data string 
     $post_data = http_build_query($req, '', '&'); 
     $sign = '75da1e3ff750286bf73d03197f1b779fbfff963fd7402941ae326509a6615eacb839b44f236b4d5ee6cff39321e7b35e9563a9a2075e99df0f4ee3b732999348'; 

     // generate the extra headers 
     $headers = array(
       'Sign: '.$sign, 
       'Key: '.$key, 
     ); 

     // our curl handle (initialize if required) 
     static $ch = null; 
     if (is_null($ch)) { 
       $ch = curl_init(); 
       curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 
       curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; Cryptsy API PHP client; '.php_uname('s').'; PHP/'.phpversion().')'); 
     } 
     curl_setopt($ch, CURLOPT_URL, 'https://api.cryptsy.com/api'); 
     curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data); 
     curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); 
     curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); 

     // run the query 
     $res = curl_exec($ch); 

     if ($res === false) throw new Exception('Could not get reply: '.curl_error($ch)); 
     $dec = json_decode($res, true); 
     if (!$dec) throw new Exception('Invalid data received, please make sure connection is working and requested API exists'); 

     echo "<pre>".print_r($dec, true)."</pre>"; 
     return $dec; 
} 

api_query(); 

При выполнении кода возвращает массив JSON значений. Я попытался реализации один и тот же код в Golang:

func PrivateCall(c appengine.Context) (map[string]interface{}, error) { 
    AuthAPI := "https://api.cryptsy.com/api" 
    APIKey := "90294318da0162b082c3d27126be80c3873955f9" 
    tr := urlfetch.Transport{Context: c} 
    values := url.Values{} 
    values.Set("method", "getinfo") 
    values.Set("nonce", "1394503747386411") 

    signature := "75da1e3ff750286bf73d03197f1b779fbfff963fd7402941ae326509a6615eacb839b44f236b4d5ee6cff39321e7b35e9563a9a2075e99df0f4ee3b732999348" 

    req, err := http.NewRequest("POST", AuthAPI+"?"+values.Encode(), nil) 
    if err != nil { 
     c.Infof("API - Call - error 2 - %s", err.Error()) 
     return nil, err 
    } 
    req.Header.Set("Key", APIKey) 
    req.Header.Set("Sign", signature) 

    c.Infof("req - %v", req) 
    resp, err := tr.RoundTrip(req) 
    if err != nil { 
     c.Errorf("API post error: %s", err) 
     return nil, err 
    } 
    defer resp.Body.Close() 
    //reading response 
    body, err := ioutil.ReadAll(resp.Body) 
    if err != nil { 
     c.Errorf("API read error: could not read body: %s", err) 
     return nil, err 
    } 
    result := make(map[string]interface{}) 
    //unmarshalling JSON response 
    err = json.Unmarshal(body, &result) 
    if err != nil { 
     c.Infof("Unmarshal: %v", err) 
     c.Infof("%s", body) 
     return nil, err 
    } 
    return result, nil 
} 

Я получаю сообщение об ошибке сказав «не удалось авторизовать запрос - Проверьте сообщение данных». Кто-нибудь видит, что могло вызвать эту ошибку? На мой взгляд, возможно, заголовок запроса в Go представляет собой строку [string] [], а в PHP - массив ...

+0

никогда не использовал golang, но сразу же я могу видеть заголовки отличаются от 'Знак: & Key:' –

+0

Пожалуйста 'идти fmt' свой код и укажите значения для переменных, выходящих за рамки. Кроме того, какая часть кода печатает ошибку? – AntoineG

+0

@LozCherone Я думаю, что ':' добавляется, потому что в PHP заголовки представляют собой массив, поэтому, чтобы превратить их в структуру, похожую на карту, вам нужно добавить ':', в то время как в Go они уже являются картой, поэтому они будут правильно напечатаны. – ThePiachu

ответ

2

Как было предложено LeGEC, вы помещаете POST в конец URL-адреса, как если бы это был запрос GET.

Попробуйте заменить

values := url.Values{} 
values.Set("method", "getinfo") 
values.Set("nonce", "1394503747386411") 

signature := "75da1e3ff750286bf73d03197f1b779fbfff963fd7402941ae326509a6615eacb839b44f236b4d5ee6cff39321e7b35e9563a9a2075e99df0f4ee3b732999348" 

req, err := http.NewRequest("POST", AuthAPI+"?"+values.Encode(), nil) 

с

data := struct { 
    method string 
    nonce string 
}{ 
    "getinfo", 
    "1394503747386411", 
} 
signature := "75da1e3ff750286bf73d03197f1b779fbfff963fd7402941ae326509a6615eacb839b44f236b4d5ee6cff39321e7b35e9563a9a2075e99df0f4ee3b732999348" 
postData, err := json.Marshal(data) 
if err != nil { 
    return nil, err 
} 
buf := bytes.NewBuffer(postData) 
req, err := http.Post(AuthAPI, "application/json", buf) 
+0

Хмм, выполнение http.Post означает, что я не могу установить заголовки http перед выполнением запроса. Я попытался добавить буфер в свой код, но это все равно приводит к тому же ответу ... – ThePiachu

+0

Хорошо, после измельчения различных подходов выяснилось, что способ добавления значений к URL-адресу был одной из проблем. – ThePiachu

0

Вот что вам нужно, и вот несколько вещей, которые вы пропустили.

  • При работе с https вам нужно установить TLSClientConfig
  • Missing X- префикса в пользовательских заголовках
  • values.Encode() является неправильной позицией.

Пример: См https://www.cryptsy.com/pages/api

var (
    urlStr = "https://api.cryptsy.com/api" 
    key = "YOUR KEY" 
    secret = "YOUR SECRECT" 
    agent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/33.0.1750.146 Safari/537.36" 
) 

func main() { 

    client := &http.Client{Transport: &http.Transport{ 
     TLSClientConfig: &tls.Config{ 
      InsecureSkipVerify: true, 
     }, 
    }} 

    values := url.Values{} 
    // $req['method'] = $method; 
    values.Set("method", "getinfo") 

    // $mt = explode(' ', microtime()); 
    // $req['nonce'] = $mt[1]; 
    values.Set("nonce", time.Nanosecond.String()) 

    // $post_data = http_build_query($req, '', '&'); 
    encoded := values.Encode() 

    mac := hmac.New(sha512.New, []byte(secret)) 
    mac.Write([]byte(encoded)) 

    //$sign = hash_hmac("sha512", $post_data, $secret); 
    sign := fmt.Sprintf("%x", mac.Sum(nil)) 

    req, err := http.NewRequest("POST", urlStr, bytes.NewBufferString(encoded)) 

    if err != nil { 
     log.Fatalln(err) 
    } 

    // generate the extra headers 
    // $headers = array(
    // 'Sign: '.$sign, 
    // 'Key: '.$key, 
    //); 
    req.Header.Set("X-Sign", sign) 
    req.Header.Set("X-Key", key) 

    // curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; Cryptsy API PHP client; '.php_uname('s').'; PHP/'.phpversion().')'); 
    req.Header.Set("User-Agent", agent) 
    req.Header.Add("Content-Type", "application/x-www-form-urlencoded") 
    req.Header.Add("Content-Length", strconv.Itoa(len(encoded))) 

    //  $res = curl_exec($ch); 
    resp, err := client.Do(req) 

    if err != nil { 
     log.Fatalln(err) 
    } 
    fmt.Println(resp.Status) 

    data, _ := ioutil.ReadAll(resp.Body) 
    fmt.Printf("%s", data) 
} 
+0

Хм, я думаю, что это будет подход, который нужно предпринять для ванильного голанга, а не GAE Go. – ThePiachu

+0

Что вы подразумеваете под 'not GAE', есть ли лучший подход к настройке заголовков с использованием' http.Post'? – Baba

+0

В GAE вы не запускаете функцию 'main', и вы не можете сделать http-вызов без использования' urlfetch', для чего требуется 'appengine.Context'. – ThePiachu

Смежные вопросы