2014-09-03 54 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