皇家邮件运送API-SOAP连接和pem/证书查询 [英] Royal Mail Shipping API - SOAP connection & pem/certificates query

查看:153
本文介绍了皇家邮件运送API-SOAP连接和pem/证书查询的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试设置Royal Mail Shipping API(如果有人对此有任何经验,如果能为您提供帮助,将不胜感激.)

I am trying to setup the Royal Mail Shipping API (if anyone has any experience of this i'd be grateful if you could assist).

在他们提供的文档中,我需要下载证书(.p12文件)&将其导入到我的Windows计算机上-使用证书导入向导"非常简单.进入设置安全级别"后,我必须选择,并且每次使用时都会要求输入密码.

In the documentation they provide I need to download a certificate (a .p12 file) & import this onto my Windows machine - this is pretty straightforward using the 'Certificate Import Wizard'. Once it gets to the "Set Security Level' I must select High & this will request permission with a password each time this is used.

在Internet Explorer的内容"选项卡中"Internet选项"中,我可以查看证书,并且可以清楚地看到此证书已导入并且尚未过期.

In Internet Explorer in 'Internet Options' within the Content tab I can view the Certificates and can clearly see that this certificate has been imported and hasn't expired.

下一步是提取证书组件,这里我必须使用OpenSSL运行以下三个命令来生成.pem文件.

The next step is to extract the certificate components, here I have to run the three following commands using OpenSSL to generate the .pem files.

$ openssl pkcs12 -in mycert.p12 -cacerts -nokeys -out cacert.pem
$ openssl pkcs12 -in mycert.p12 -clcerts -nokeys -out mycert.pem
$ openssl pkcs12 -in mycert.p12 -nocerts -nodes -out mykey.pem 

文档指出, cacert.pem文件可以由应用程序使用文件本身直接引用,我相信我已经在我的PHP脚本中完成过此操作,但是尚不清楚我应该在哪里放置另一个 mycert& mykey pem文件.

The documentation states the cacert.pem file can be directly referenced by an application using the file itself, which I believe I have done within my PHP script however it isn't clear where I should put the other mycert & mykey pem files.

文档对此有以下说明:-

The documentation states the following in regards to this :-

在建立与应用程序和环境的SSL网络连接时,应用程序如何通过已发行的客户端SSL证书,但它本质上需要同时访问"mycert.pem"和"mykey.pem"文件,或者在某些情况下,一个包含cert和key的组合文件.

How an application passes the issued client SSL certificate when establishing an SSL network connection to is application and environment dependent but it would essentially need to access both the "mycert.pem" and "mykey.pem" file, or in some cases, a single combined file containing both cert and key.

因此,在我将它们与cacert.pem文件放在同一目录中的那一刻,它无处说明应用程序如何使用这两个文件.

So nowhere does it say how these two files are used by the application, at the moment I've just left them in the same directory as the cacert.pem file.

如果我尝试访问网址 https://api.royalmail.com/shipping/onboarding 直接从浏览器,它要求我选择一个证书,我选择此&然后在要求授予或拒绝使用此密钥的权限"时输入正确的密码.输入正确的密码后,将显示以下页面-任何人都可以确认这是否意味着问题已在我端或皇家邮政未在其端正确配置.

If I try to access the url https://api.royalmail.com/shipping/onboarding directly from the browser, it asks for me to select a certificate, I select this & then enter the correct password when it asks to 'Grant or deny permission to use this key'. Once I enter the correct password the following page appears - can anyone confirm if this would mean the issue is at my end OR something that Royal Mail hasn't configured correctly at their end.

除此之外,我拥有的用于将SOAP请求发送到Shipping API的实际PHP脚本无法正常工作(可能与上述所有内容有关).

In addition to this, the actual PHP script that I have that is used to send SOAP requests to the Shipping API isn't working (probably related to everything above).

在我的PHP脚本中,soapclient选项设置如下:

Within my PHP script the soapclient options are set up as follows:

$soapclient_options['cache_wsdl'] = 'WSDL_CACHE_NONE'; 
$soapclient_options['local_cert'] = 'certs/cacert.pem';
$soapclient_options['passphrase'] = $api_certificate_passphrase;
$soapclient_options['trace'] = true;
$soapclient_options['ssl_method'] = 'SOAP_SSL_METHOD_SSLv3';
$soapclient_options['location'] = 'https://api.royalmail.com/shipping/onboarding';

$client = new SoapClient('SAPI/ShippingAPI_V2_0_8.wsdl', $soapclient_options);
$client->__setLocation($soapclient_options['location']);

当我运行PHP脚本时(这与Royal Mail提供自己的个人API登录详细信息的代码基本相同),我在浏览器中收到以下消息:

When I run the PHP script (this is basically the same code that Royal Mail provide themselves with my own personal API login details) I get the following message in the browser:

Could not connect to host 
REQUEST: email@yoursite.co.ukAPI rngfJ+4dt4Gt855a5pr6u38i3B4= ODcwMTE5Nzc3 2015-10-13T11:02:20Z 2015-10-13T11:02:201.00526348001DeliveryDSD12015-10-13bobSS23, Some AvenueLondonE10g1000000

显然,由于某些未知原因,它无法连接到主机,后者只是发送的请求. PHP脚本的其余部分与他们发送给我&的皇家邮件的脚本完全相同.已经确认被他人使用并且可以正常工作.

Obviously this cannot connect to the host for some unknown reason, the latter is simply the request that was sent. The rest of the PHP script is exactly the same as the Royal Mail's script they sent to me & have confirmed is used by others and working fine.

尽管最终的代码将在Linux环境中,但我正在WAMP环境中工作. 任何人都可以帮忙 Royal Mail本身还无法提供任何可靠的技术支持.

I am working in a WAMP environment although the eventual code will be in a Linux environment. Can anyone help I am really getting baffled & Royal Mail themselves haven't been able to provide any solid technical support yet.

这是浏览器中显示的完整错误消息(出于安全目的,我已更改了电子邮件地址)

This is the full error message displayed in the browser (i've changed the email address for security purposes)

Invalid Request REQUEST: myemail@company.co.ukAPI dgCW98Vqw3ladYgPPpNialODhvI= MTMzMjE1NjM4 2015-10-13T13:25:30Z 2015-10-13T13:25:302.00526348001DeliveryDSD12015-10-13Jon DoeSS23, Some RoadLondonE10g1000000

我已将两个pem文件合并为一个名为"bundle.pem"的文件,在SoapClient&的'local_cert'变量中引用了此内容. BINGO现在正在连接.现在,这更长了,显示了无法连接,而是显示了无效请求",因此至少现在这正在连接并给我一个不同的错误.

I've merged the two pem files into a single file called 'bundle.pem' & referenced this in the 'local_cert' variable for the SoapClient & BINGO this is now connecting. This now longer shows the Could not connect but states an 'Invalid Request' instead, so at least now this is connecting and giving me a different error.

我的整个PHP脚本如下:

My entire PHP script is below:

<?php

ini_set('default_socket_timeout', 120);
ini_set('soap.wsdl_cache_enabled',1);
ini_set('soap.wsdl_cache_ttl',1);

$api_password = "xxxxxxxxxxxxxx!";
$api_username = "xxxxxxxxx@xxxxxxxxx.co.ukAPI";
$api_application_id = "xxxxxxxxxxxx";
$api_service_type = "D";
$api_service_code = "SD1";
$api_service_format = "";
$api_certificate_passphrase = 'xxxxxxxxxx';
$api_service_enhancements = "";

$data = new ArrayObject();
$data->order_tracking_id = "";
$data->shipping_name = "Jon Doe";
$data->shipping_company = "SS";
$data->shipping_address1 = "23, Some Road"; 
$data->shipping_address2 = "";
$data->shipping_town = "London";
$data->shipping_postcode = "E1";
$data->order_tracking_boxes = "0";
$data->order_tracking_weight = "1000";    

$time = gmdate('Y-m-d\TH:i:s');
$created = gmdate('Y-m-d\TH:i:s\Z');
$nonce = mt_rand();
$nonce_date_pwd = pack("A*",$nonce) . pack("A*",$created) . pack("H*", sha1($api_password));
$passwordDigest = base64_encode(pack('H*',sha1($nonce_date_pwd)));
$ENCODEDNONCE = base64_encode($nonce);


$soapclient_options = array(); 
$soapclient_options['cache_wsdl'] = 'WSDL_CACHE_NONE'; 
$soapclient_options['local_cert'] = 'royalmail/cert/bundle.pem';
$soapclient_options['passphrase'] = $api_certificate_passphrase;
$soapclient_options['trace'] = true;
$soapclient_options['ssl_method'] = 'SOAP_SSL_METHOD_SSLv3';
$soapclient_options['exceptions'] = true;
$soapclient_options['location'] = 'https://api.royalmail.com/shipping/onboarding';

//launch soap client
$client = new SoapClient('royalmail/ShippingAPI_V2_0_8.wsdl', $soapclient_options);
$client->__setLocation($soapclient_options['location']);

//headers needed for royal mail
$HeaderObjectXML  = '<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
                      xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
           <wsse:UsernameToken wsu:Id="UsernameToken-000">
              <wsse:Username>'.$api_username.'</wsse:Username>
              <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">'.$passwordDigest.'</wsse:Password>
              <wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">'.$ENCODEDNONCE.'</wsse:Nonce>
              <wsu:Created>'.$created.'</wsu:Created>
           </wsse:UsernameToken>
       </wsse:Security>';

//push the header into soap
$HeaderObject = new SoapVar( $HeaderObjectXML, XSD_ANYXML );

//push soap header
$header = new SoapHeader( 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd', 'Security', $HeaderObject );
$client->__setSoapHeaders($header);

//build the request
$request = array(
    'integrationHeader' => array(
        'dateTime' => $time,
        'version' => '1.0',
        'identification' => array(
            'applicationId' => $api_application_id,
            'transactionId' => $data->order_tracking_id
        )
    ),
    'requestedShipment' => array(
                                'shipmentType' => array('code' => 'Delivery'),
                                'serviceOccurence' => '1',
                                'serviceType' => array('code' => $api_service_type),
                                'serviceOffering' => array('serviceOfferingCode' => array('code' => $api_service_code)),
                                'serviceFormat' => array('serviceFormatCode' => array('code' => $api_service_format)),
                                'shippingDate' => date('Y-m-d'),
                                'recipientContact' => array('name' => $data->shipping_name, 'complementaryName' => $data->shipping_company),
                                'recipientAddress' => array('addressLine1' => $data->shipping_address1,  'addressLine2' => $data->shipping_address2, 'postTown' => $data->shipping_town, 'postcode' => $data->shipping_postcode),
                                'items' => array('item' => array(
                                            'numberOfItems' => $data->order_tracking_boxes,
                                            'weight' => array( 'unitOfMeasure' => array('unitOfMeasureCode' => array('code' => 'g')), 'value' => ($data->order_tracking_weight*1000) //weight of each individual item
                                                             )
                                                                )
                                                )
                                )               
);


//if any enhancements, add it into the array
if($api_service_enhancements != "") {
    $request['requestedShipment']['serviceEnhancements'] = array('enhancementType' => array('serviceEnhancementCode' => array('code' => $api_service_enhancements)));
}

//try make the call
try { 
    $response = $client->__soapCall( 'createShipment', array($request), array('soapaction' => 'https://api.royalmail.com/shipping/onboarding') );
} catch (Exception $e) {
    //catch the error message and echo the last request for debug
    echo $e->getMessage(); 
    echo " REQUEST:\n" . $client->__getLastRequest() . "\n";
    die;
}

//check for any errors
if(isset($response->integrationFooter->errors)) { 
    $build = "";

    //check it wasn't a single error message
    if(isset($response->integrationFooter->errors->error->errorCode)) { 
        $build .= $output_error->errorCode.": ".$output_error->errorDescription."<br/>"; 
    } else {
        //loop out each error message, throw exception will be added ehre
        foreach($response->integrationFooter->errors->error as $output_error) { 
            $build .= $output_error->errorCode.": ".$output_error->errorDescription."<br/>";
        }
    }

    echo $build; die;

}

print_r($response);

echo "REQUEST:\n" . $client->__getLastRequest() . "\n";
die;            
?>

为了更加清晰起见,我在$ request变量到达try/catch块之前添加了一个转储(注意这有点长).

Just for additional clarity I've added a dump of the $request variable just before it reaches the try/catch block (note this is kinda long).

Array
(
    [integrationHeader] => Array
        (
        [dateTime] => 2015-10-13T13:34:44
        [version] => 1.0
        [identification] => Array
            (
                [applicationId] => 0526348001
                [transactionId] => 
            )

    )

[requestedShipment] => Array
    (
        [shipmentType] => Array
            (
                [code] => Delivery
            )

        [serviceOccurence] => 1
        [serviceType] => Array
            (
                [code] => D
            )

        [serviceOffering] => Array
            (
                [serviceOfferingCode] => Array
                    (
                        [code] => SD1
                    )

            )

        [serviceFormat] => Array
            (
                [serviceFormatCode] => Array
                    (
                        [code] => 
                    )

            )

        [shippingDate] => 2015-10-13
        [recipientContact] => Array
            (
                [name] => Jon Doe
                [complementaryName] => SS
            )

        [recipientAddress] => Array
            (
                [addressLine1] => 23, Some Road
                [addressLine2] => 
                [postTown] => London
                [postcode] => E1
            )

        [items] => Array
            (
                [item] => Array
                    (
                        [numberOfItems] => 0
                        [weight] => Array
                            (
                                [unitOfMeasure] => Array
                                    (
                                        [unitOfMeasureCode] => Array
                                            (
                                                [code] => g
                                            )

                                    )

                                [value] => 1000000
                            )

                    )

            )

    )

)

推荐答案

首先,访问 https://api.royalmail.com/shipping/onboarding 直接不起作用,因为只能通过API进行访问.

Firstly, accessing the https://api.royalmail.com/shipping/onboarding directly will not work, because it's only accessible via the API.

使用Royal Mail,您是否拥有所有CDM文件和WSDL文件?确保CDM文件与WSDL文件位于同一目录中.

With Royal Mail, do you have all of the CDM files and WSDL files? Make sure the CDM files are in the same directory as the WSDL files.

这是我使用API​​时所做的;

Here's what I did when working with the API;

$client = new SoapClient("/royalmail/ShippingAPI_V2_0_8.wsdl", array(
                                                    'trace' => 1,
                                                    'location'   => $location, //https://api.royalmail.com/shipping
                                                    'soap_version' => SOAP_1_1,
                                                    'local_cert' => '/royalmail/cert/cert.pem',
                                                    'passphrase' => 'xxx',
                                                    'exceptions' => true
                                                ));

然后,在实际建立连接时,我做了这样的事情:

Then, when it came to actually making the connection, I did something like this:

    $password = 'xxx';

    $date = gmdate('Y-m-d\TH:i:s\Z');
    $nonce = mt_rand();
    $nonce_date_pwd = pack("A*",$nonce) . pack("A*",$date) . pack("H*", sha1($password));
    $encoded_password = base64_encode(pack('H*',sha1($nonce_date_pwd)));
    $encoded_nonce = base64_encode($nonce);

    $HeaderObjectXML  = '<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
                              xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
                   <wsse:UsernameToken wsu:Id="UsernameToken-0000">
                      <wsse:Username>Username</wsse:Username>
                      <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">' . $encoded_password . '</wsse:Password>
                      <wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">' . $encoded_nonce . '</wsse:Nonce>
                      <wsu:Created>'.$date.'</wsu:Created>
                   </wsse:UsernameToken>
               </wsse:Security>';

    $HeaderObject = new SoapVar( $HeaderObjectXML, XSD_ANYXML );

    $header = new SoapHeader( 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd', 'Security', $HeaderObject );
    $client->__setSoapHeaders( $header );

    $request = array('the shipment request');

    try {
        $client->__soapCall( 'createShipment', array($request) );
    }
    catch (SoapFault $soapFault) {
       print_r($soapFault);
    }

我希望这会有所帮助.

修改

尝试此请求

认为,如果我没有记错的话,那么您需要使用版本2进行该服务.另外,只是...格式化.使调试变得更容易.

I think you need to use Version 2 for that Service Occurrence, if I remember rightly. Also, just...formatting. Makes it easier to debug.

$request = Array(

    'integrationHeader' => array(
        'dateTime' => date('Y-m-d\TH:i:s'),
        'version' => '2',
        'identification' => array(
            'applicationId' => $api_application_id,
            'transactionId' => $data->order_tracking_id
        ),

    ),

    'requestedShipment' => array(   
        'shipmentType' => array(
            'code' => 'Delivery'
        ),
    'serviceOccurrence' => 1,
        'serviceType' => array(
            'code' => $api_service_type
        ),
        'serviceOffering' => array(
            'serviceOfferingCode' => array(
                'code' => $api_service_code
            )
        ),
        'serviceFormat' => array(
            'serviceFormatCode' => array(
                'code' => $api_service_format
            )
        ),
        'shippingDate' => gmdate('Y-m-d'),
        'recipientContact' => array(
            'name' => $data->shipping_name,
            'complementaryName' => $data->shipping_company
        ),
        'recipientAddress' => array(
            'addressLine1' => $data->shipping_address1,
            'addressLine2' => $data->shipping_address2,
            'postTown' => $data->shipping_town,
            'postcode' => $data->shipping_postcode
        ),
        'items' => array(
            'item' => array(
                'numberOfItems' => $data->order_tracking_boxes,
                'weight' => array(
                    'unitOfMeasure' => array(
                        'unitOfMeasureCode' => array(
                            'code' => 'g'
                        )
                    ),
                    'value' => ($data->order_tracking_weight*1000)
                )
            )
        )

    )
);

这篇关于皇家邮件运送API-SOAP连接和pem/证书查询的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆