Python POST请求相同的JS / PHP

时间:2014-09-03 10:33:56

标签: javascript php python http-post

我在js / php方面不擅长,但我需要将下面的代码转换为Python。

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 个答案:

答案 0 :(得分:1)

嗯,我猜您的问题是身份验证。你没有在Python中展示你是如何做到这一点的,但我想有一些关于它的东西,因为你甚至在你有一个正文(body_md5_str调用之前)以某种方式计算signaturejson.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编码数据。