2014-09-03 49 views
1

我不擅長js/php,但我需要將以下代碼轉換爲Python。Python POST請求相同JS/PHP

的JavaScript版本:

function api_query(key,keyId,url,post,body,signature,cb){var method='POST'; 
    var date=new Date(); 
    var content_type='application/x-www-form-urlencoded; charset=UTF-8;'; 
    var body_md5=CryptoJS.MD5(body); 
    var http= new XMLHttpRequest();http.onreadystatechange=function(){if (http.readyState===4){cb(JSON.parse(http.responseText));}}; 
    http.open("POST",'http://'+url,true);http.setRequestHeader('x-pbx-date',date); 
    http.setRequestHeader('Accept','application/json'); 
    http.setRequestHeader('Content-Type',content_type); 
    http.setRequestHeader('Content-MD5',body_md5); 
    http.setRequestHeader('x-pbx-authentication',keyId+':'+signature); 
    http.send(body);} 

PHP版本:

$post = http_build_query($post); 
    $content_type = 'application/x-www-form-urlencoded'; 
    $content_md5 = hash('md5', $post); 
    $signature = base64_encode(hash_hmac('sha1', $method."\n".$content_md5."\n".$content_type."\n".$date."\n".$url."\n", $secret_key, false)); 
    $headers = array('Date: '.$date, 'Accept: application/json', 'Content-Type: '.$content_type, 'x-pbx-authentication: '.$key_id.':'.$signature, 'Content-MD5: '.$content_md5); 

    if (isset($opt['secure']) && $opt['secure']){ 
     $proto = 'https'; 
    }else{ 
     $proto = 'http'; 
    } 
    $ch = curl_init($proto.'://'.$url); 
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 
    curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST'); 
    curl_setopt($ch, CURLOPT_POST, true); 
    curl_setopt($ch, CURLOPT_POSTFIELDS, $post); 
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); 
    curl_setopt($ch, CURLOPT_TIMEOUT, 60); 
    $res = json_decode(curl_exec($ch), true); 
    if ($res){return $res;}else{return false;} 

心中已經試過請求庫:

headers = { 
    'x-pbx-date': date, 
    'Content-Type': content_type, 
    'Content-MD5': body_md5_str, 
    'x-pbx-authentication': signature, 
} 
payload = { 
    'date_from': date_from, 
    'date_to': date_to, 
} 
r = requests.post(url, data=json.dumps(payload), headers=headers) 

httlib2:

http = httplib2.Http() 
response, content = http.request(url, 'POST', headers=headers, body=urllib.urlencode(payload)) 

的urllib2:

req = urllib2.Request(url, data=urllib.urlencode(payload), headers=headers) 
response = urllib2.urlopen(req).read() 

沒有什麼工作。在每個嘗試服務器響應:未驗證。有任何想法嗎?

回答

1

嗯,我想你的問題是身份驗證。你沒有說明你是怎麼用Python做的,但是我想這是有關的,因爲你在計算body_md5_strsignature之前,甚至有一個機構(json.dumps調用),所以一定有什麼問題。你確定你的代碼生成與JS和PHP代碼相同的值嗎?

就我個人而言,我會實現一個認證類,它會在請求觸發前添加必要的頭文件。請參閱requests documentation on custom auth的細節,這裏是它我的(未經測試)的嘗試,如果我得到正確的細節:

import requests 
import hashlib 
import hmac 
import base64 
from wsgiref.handlers import format_date_time 
import datetime 
from time import mktime 

CONTENT_TYPE_FORM_URLENCODED = "application/x-www-form-urlencoded" 

class OnlinePBXAuth(requests.auth.AuthBase): 
    def __init__(self, key_id, secret): 
     self.key_id = key_id 
     self.secret = secret 

    def __call__(self, r): 
     content_type = r.headers.get("Content-Type", CONTENT_TYPE_FORM_URLENCODED) 
     body = r.body or "" 
     body_md5 = hashlib.md5(body).hexdigest() 
     date = format_date_time(mktime(datetime.datetime.now().timetuple())) 
     date = r.headers.get("Date", date) 
     r.headers["Date"] = date 
     r.headers["X-PBX-Date"] = date 
     sign = "\n".join([r.method, body_md5, content_type, date, r.url, ""]) 
     signature = base64.b64encode(hmac.new(self.secret, sign, hashlib.sha1).hexdigest()) 
     r.headers["Content-MD5"] = body_md5 
     r.headers["X-PBX-Authentication"] = "{0}:{1}".format(self.key_id, signature) 
     return r 

不是最漂亮的代碼,但我想這應該做的伎倆。

然後,使用這樣的:

auth = OnlinePBXAuth(KEY_ID, KEY_SECRET) 
... 
data = {"date_from": date_from, "date_to": date_to} 
r = requests.post(url, data, auth=auth) 
... 

,或者甚至是這樣的:

session = requests.Session(auth=OnlinePBXAuth(KEY_ID, KEY_SECRET)) 
... 
r1 = session.post(url, data) 
... 
r2 = session.post(another_url, another_data) 

我不知道它會與空健全工作要求(最喜歡的GET是)和多部分塊體雖然(如你自己的圖或只是試圖避免這些),但我想應該可以應用/ x-www-form-urlencoded和application/json編碼數據。

+0

是的,我絕對確保我的代碼生成與php/js ceteris paribus相同的值。我通過Chrome逐步調試發現它。相同的md5散列和簽名。您的代碼會返回:'{「status」:0,「comment」:「not authenticated」,「data」:「」}' [Api examples and php/js library links in Russian](http://api.onlinepbx .ru /) – 2014-09-03 12:47:36

+0

嗯......猜猜我錯了,然後。抱歉。不幸的是,我沒有發現代碼有什麼問題。那麼,有一個服務[RequestBin](http://requestb.in/),顯示對它的HTTP請求。也許值得嘗試指出PHP和Python程序(固定日期,因此請求將完全相同),並將請求與相同的數據進行比較?也許它會給出一些線索,Python版本可能會出錯。 – drdaeman 2014-09-03 12:55:46

+0

Ogh,在我的代碼中生成的signature_str中有一次'\ n'符號。所有方法,包括你的工作。 Ty求助。 – 2014-09-03 13:43:55