使用 Perl 发送 CURL 请求到 PayMill

4
我对curl一无所知。 我想把PayMill集成到我的网站中(网站使用Perl编写)。 目前尚未有适用于Paymill的Perl库,因此需要通过curl连接到Paymill。
我已经完成了前端JS Paymill集成,并从PayMill接收到付款令牌。
现在,我需要将从Paymill接收到的令牌传递给后端,并使用curl向PayMill请求完成交易并向用户收费。但我卡在这一步了。
根据PayMill文档,要进行交易,必须执行以下操作:
curl https://api.paymill.de/v2/transactions \
-u b94a7550bd908877cbae5d3cf0dc4b74: \
-d "amount=4200" \
-d "currency=EUR" \
-d "token=098f6bcd4621d373cade4e832627b4f6" \
-d "description=Test Transaction"

我认为-u是Paymill的秘密键,用于验证我的请求,尽管文档在这里并不清楚。

我已经查看了WWW::Curl::Easy、Net:Curl::Easy和LWP::Curl,但是这些方法的文档中没有明确说明如何形成上面的查询。

我尝试过(虽然并不相信会成功),只是像上面描述的那样在perl中对字符串进行编码;

my $request = '-u ' . $private_key . " ";
foreach my $key (keys %$params_in) {
    $request .= '-d "' . lc($key) .'='.$params_in->{$key} . ' ';
}

然后将$request传递给我的curl尝试,代码如下:

my $curl = WWW::Curl::Easy->new;
$curl->setopt(WWW::Curl::Easy::CURLOPT_HEADER(), 1);
$curl->setopt(WWW::Curl::Easy::CURLOPT_URL(), $paymill_server);
$curl->setopt(WWW::Curl::Easy::CURLOPT_POST(), 1);
$curl->setopt(WWW::Curl::Easy::CURLOPT_POSTFIELDS(), $request);

my $response;
$curl->setopt(WWW::Curl::Easy::CURLOPT_WRITEDATA(), \$response);

my $retcode = $curl->perform;

然而,这会导致“访问被拒绝”的错误,我想是因为Paymill没有找到我的密钥,因为我在Curl中搞错了(假设-u应该是secret_key)。
我感觉我缺少一些显而易见的东西。
请问有人能指点我如何处理吗? 谢谢。
非常好的答案,感谢大家的帮助,现在它正在工作。最终我选择了Matthias的解决方案,完整的交易解决方案如下;
use LWP::UserAgent;
use MIME::Base64;
use JSON::XS;

my $ua = LWP::UserAgent->new;
$ua->default_header(Authorization => "Basic " . encode_base64(private_key));

my $response = $ua->post(https://api.paymill.de:443/v2/transactions , $params );
if ( $response->is_success ) {
    my $obj = eval { decode_json $response->content } || {};
    etc
}

我认为你可以使用LWP和Curl相对容易地完成这个任务。我不太熟悉Curl,所以你的代码看起来比较难读懂。-u选项用于向请求中添加凭据(例如用户名/密码)(请参见http://curl.haxx.se/docs/manpage.html#-u)。 - simbabque
1
首先确保您可以从命令行使用curl成功发出请求;然后再尝试将其集成到您的Perl代码中。 - ysth
3个回答

4
像其他答案建议的那样,最好使用LWP::UserAgent来进行请求。注意:自从PAYMILL推出挑战响应以来,代码已经有所更新。由于PAYMILL不符合RFC 2616第14.47节(API未发送挑战响应),因此LWP :: UserAgent等工具在发送第二个带证书的请求时会失败。解决方案是通过将它们添加为标头,强制LWP::UserAgent在第一个请求中发送证书。
use LWP::UserAgent;
use MIME::Base64;

my $ua = LWP::UserAgent->new;
# Use the following line no longer:
# $ua->default_header(Authorization => "Basic " . encode_base64("your PRIVATE key"))
$ua->credentials('api.paymill.de:443', '', 'YOUR PRIVATE KEY');

# Dumping only
use Data::Dumper;
print Dumper($ua->get("https://api.paymill.de:443/v2/clients"));

声明:我在 Paymill 工作。


2

我不确定用户/密码和令牌的认证部分是否正确,因为我不知道“Realm”应该是什么。不过,你可以试试LWP。虽然我并不讨厌Curl,但我确实不熟悉它,但我熟悉LWP。

use strict; use warnings;
use LWP::UserAgent;
my $ua = LWP::UserAgent->new;
$ua->credentials(
  'api.paymill.de:80',
  'Realm?',
  'b94a7550bd908877cbae5d3cf0dc4b74'
);
my $response = $ua->post(
  ' https://api.paymill.de/v2/transactions',
  {
    amount      => "4200",
    currency    => "EUR",
    token       => "098f6bcd4621d373cade4e832627b4f6",
    description => "Test Transaction",
  }
);
if ( $response->is_success ) {
  print $response->decoded_content;    # or whatever
} else {
  die $response->status_line;
}

编辑:我在Paymill文档中看到了一些内容。它说:

Authentication

Example

% curl https://api.paymill.de/v2/clients \ -u e73fa5e7b87620585b5ea5d73c4d23bb:

To authenticate at the Paymill API, you need the private key of your test or live account. You have to use http basic access authentification. Your key has to be set as the username. A password isn’t required and you don’t have to insert one. But if you want, feel free to insert an arbitrary string.

Note

Please keep your private keys secure and don’t pass them to anybody. These private keys have extreme secure information for

handling the transactions of your shop. All your requests must be made via https. Requests which will be made in another way will fail. This is for security reasons of the submitted data.

还有一个链接指向http://en.wikipedia.org/wiki/HTTP_Secure,我相信它可以很好地解释-u的含义。

2

您可以使用LWP::Protocol::Net::Curl有机地集成LWP和libcurl。请参考以下内容:

#!/usr/bin/env perl
use common::sense;

use Data::Printer;
use JSON::XS;
use LWP::Protocol::Net::Curl verbose => 1;
use LWP::UserAgent;

# create user agent
my $ua = LWP::UserAgent->new;

# POST request
my $res = $ua->post(
    'https://b94a7550bd908877cbae5d3cf0dc4b74:@api.paymill.de/v2/transactions',
    'Accept-Encoding' => 'gzip',
    Content => {
        amount      => 4200,
        currency    => 'EUR',
        token       => '098f6bcd4621d373cade4e832627b4f6',
        description => 'Test Transaction',
    },
);

# parse received data
my $obj = eval { decode_json $res->content } // {};

# output
p $obj;

输出结果:
* About to connect() to api.paymill.de port 443 (#0)
*   Trying 62.138.241.3...
* Connected to api.paymill.de (62.138.241.3) port 443 (#0)
* Connected to api.paymill.de (62.138.241.3) port 443 (#0)
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: none
* SSL connection using RC4-SHA
* Server certificate:
*    subject: OU=Domain Control Validated; OU=PositiveSSL Wildcard; CN=*.paymill.de
*    start date: 2012-07
*    expire date: 2013-10
*    subjectAltName: api.paymill.de matched
*    issuer: C=GB; S
*    SSL certificate verify ok.
* Server auth using Basic with user 'b94a7550bd908877cbae5d3cf0dc4b74'
> POST /v2/transactions HTTP/1.1
Authorization: Basic Yjk0YTc1NTBiZDkwODg3N2NiYWU1ZDNjZjBkYzRiNzQ6
User-Agent: libwww-perl/6.04 libcurl/7.28.0 OpenSSL/1.0.0e zlib/1.2.3.4 libidn/1.22 libssh2/1.2.8
Host: api.paymill.de
Accept: */*
Accept-Encoding: gzip
Content-Length: 92
Content-Type: application/x-www-form-urlencoded

* upload completely sent off: 92 out of 92 bytes
< HTTP/1.1 200 OK
< Server: nginx
< Date: Wed, 09 Jan 2013 17:22:54 GMT
< Content-Type: application/json
< Transfer-Encoding: chunked
< Connection: close
< Set-Cookie: PHPSESSID=rmdo5a8c6u107gma28lotmmn24; path=/
< Expires: Thu, 19 Nov 1981 08:52:00 GMT
< Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
< Pragma: no-cache
< X-Server: hrtt-frn5-de13
< 
* Closing connection #0
Printing in line 28 of paymill.pl:
\ {
    data   {
        amount             4200,
        client             {
            created_at     1357752174,
            description    undef,
            email          undef,
            id             "client_85cb0bfc837f31c81015",
            payment        [],
            subscription   undef,
            updated_at     1357752174
        },
        created_at         1357752174,
        currency           "EUR",
        description        "Test Transaction",
        id                 "tran_c672daa0538e2a04e919",
        livemode           false,
        origin_amount      4200,
        payment            {
            card_holder    undef,
            card_type      "visa",
            client         "client_85cb0bfc837f31c81015",
            country        undef,
            created_at     1357752174,
            expire_month   12,
            expire_year    2014,
            id             "pay_2732689f44928301c769",
            last4          1111,
            type           "creditcard",
            updated_at     1357752174
        },
        preauthorization   undef,
        refunds            undef,
        status             "closed",
        updated_at         1357752174
    },
    mode   "test"
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接