php和python结合 php和python异步并发
本教程详细阐述了将Python requests.post请求转换为PHP时常遇到的陷阱,特别是当POST请求体中包含JSON字符串作为表单字段值时。通过FedEx包裹追踪API的实际案例,我们演示了如何正确构造PHP请求,承认“UNSUPPORTED.ACTION”错误,确保数据以application/x-www-form-urlencoded格式发送,同时获取的JSON数据能被正确处理。跨语言API调用与Python的挑战请求机制解析
在现代软件开发中,不同语言之间进行调用API转换是常见的任务。Python的请求库改进简洁逻辑而广受欢迎,但在将其请求逻辑移植到PHP等其他语言时,尤其是在处理POST请求体格式方面,开发者经常会遇到一有点紧张但关键的差异。
以 FedEx 包裹追踪 API 为例,原始Python脚本使用requests.post方法,并通过数据参数提交请求体。理解requests库中数据和json参数区别的关键:requests.post(url, data=...):当data参数是一个字典时,requests库会默认将编码为application/x-www-form-urlencoded格式的表单数据发送。如果字典中的某个值本身是一个JSON字符串(例如通过json.dumps()生成),就会作为该表单字段的值被发送。requests.post(url, json=...):当使用json参数时,requests库将整个对象序列化为JSON字符串,并设置Content-Type: application/json头,将其作为请求体发送。
在提供的Python脚本中,关键部分是:data = requests.post('https://www.fedex.com/trackingCal/track', data={ 'data': json.dumps({ # 注意这里,'data'字段的值是一个JSON字符串 'TrackPackagesRequest': { # ... 追踪信息 ... } }), 'action': 'trackpackages', '语言环境': 'en_US', '格式': 'json', '版本': 99}).json()登录后复制
这里,Python脚本实际上发送的是一个application/x-www-form-urlencoded格式的请求,其中包含多个字段,如action、locale、format、version,以及一个名为data的字段,其值是一个经过JSON编码的字符串。
立即学习“PHP免费学习笔记(研究)”;PHP请求的常见错误区与“UNSUPPORTED.ACTION”错误
在将上述Python逻辑转换为PHP时,一个常见的错误是以为整个POST请求体都应该以JSON格式发送。开发者可能会尝试将包含所有参数的PHP导入整体进行json_encode,并设置Content-Type: application/json头。
以下是尝试转换时可能出现的错误PHP代码示例:lt;?php// ... 引入autoload.php ...$tracking_number = '123456789';$url = 'https://www.fedex.com/trackingCal/track';$headers = ['Content-Type' =gt; 'application/json']; // 头部设置的错误$requestData = [ //整个请求体被构建为一个 PHP 数据库 'data' =gt; [ // 这里的 'data' 字段值仍然是 PHP 数据库 'TrackPackagesRequest' =gt; [ 'appType' =gt; 'wtrk', 'uniqueKey' =gt; '', 'processingParameters' =gt; [ 'anonymousTransaction' =gt; true, 'clientId' =gt; 'WTRK', 'returnDetailedErrors' =gt; true, 'returnLocalizedDateTime' =gt; false], 'trackingInfoList' =gt; [ [ 'trackNumberInfo' =gt; [ 'trackingNumber' =gt; $tracking_number, 'trackingQualifier' =gt; '', 'trackingCarrier' =gt; '' ] ] ] ] ], 'action' =gt; 'trackpackages', 'locale' =gt; 'en_US', 'format' =gt; 'json', 'version' =gt; 99];//整个requestData备份被json_encode,并作为请求体发送$response = Requests::post($url, $headers, json_encode($requestData)); print_r($response);登录后复制
当执行bephp代码时,FedEx API会返回以下错误:{ quot;CALErrorquot;: { “代码”:“UNSUPPORTED.ACTION”,“消息”:“不支持
ed action”;, ”rootCause”;:null }}登录后复制
这个错误表明API没有识别出所请求的“action”。根本原因是,PHP脚本发送的请求体是application/json格式,而API期望的是application/x-www-form-urlencoded格式,并且其中一个表单字段(数据)的值是JSON字符串。API无法正确解析整个JS ON体来找到预期的表单字段。正确的PHP请求构造方法
解决此问题的关键在于准确模拟Python脚本发送的请求格式。这意味着:整个POST请求体应该以application/x-www-form-urlencoded格式发送。其中一个名为data的表单字段,其值必须是一个JSON编码的字符串。
使用PHP Requests库(或直接使用cURL),当Requests::post方法的个参数是一个关联阵列时,它会默认将其第三编码为application/x-www-form-urlencoded格式。因此,我们只需要对阵列中data键的值进行json_encode。
以下是修改后的PHP代码示例:lt;?php$dir = __DIR__;include $dir .'/vendor/autoload.php'; //确保Composer自动加载已配置$tracking_number = '123456789'; //替换为实际的追踪号码$url = 'https://www.fedex.com/trackingCal/track';//不需要设置Content-Type: application/json 头,因为我们发送的是form-urlencodedData$headers = []; $data = [ // 关键:只有'data'字段的值需要被json_encode quot;dataquot; =gt; json_encode([ quot;TrackPackagesRequestquot; =gt; [ quot;appTypequot; =gt; quot;wtrkquot;, quot;uniqueKeyquot; =gt; quot;quot;, quot;processingParametersquot; =gt; [ quot;anonymousTransactionquot; =gt; true, "clientId" =gt; "WTRK", "returnDetailedErrors" =gt; true, "returnLocalizedDateTime" =gt; false ], "trackingInfoList" =gt; [[ "trackNumberInfo" =gt; [ "trackingNumber" =gt; $tracking_number, "trackingQualifier" =gt; ", "trackingCarrier" =gt; "] ]] ]), "action" =gt; "trackpackages", "locale" =gt; "en_US", "format" =gt; "json", "version" =gt; 99];// 请求::post 方法会默认将$data数组编码为application/x-www-form-urlencoded$response = Requests::post($url, $he
aders, $data);//检查响应状态码 if ($response-gt;status_code === 200) { // 解析JSON响应 $responseData = json_decode($response-gt;body, true); if (isset($responseData['TrackPackagesResponse']['packageList'][0])) { $packageInfo = $responseData['TrackPackagesResponse']['packageList'][0]; $fedex_status = $packageInfo['keyStatus']; $fedex_details = $packageInfo['statusWithDetails']; $delivery_date = $packageInfo['displayActDeliveryDt']; $delivery_time = $packageInfo['displayActDeliveryTm']; echo quot;FedEx状态: quot; . $fedex_status 。 PHP_EOL; echo quot;详细信息: quot; . $fedex_details 。 PHP_EOL; echo quot;预计/实际投递日期: quot; . $delivery_date 。 PHP_EOL; echo quot;预计/实际投递时间: quot; . $delivery_time 。 PHP_EOL; } else { echo quot;未找到包裹信息或响应结构不符。quot; . PHP_EOL; }} else { echo quot;请求失败,HTTP状态码: quot; . $response-gt;status_code . PHP_EOL; echo quot;响应体: quot; . $response-gt;正文 . PHP_EOL;}登录后复制
代码将$data转发直接发送给Requests::post方法。请求库会识别是一个关联队列,并自动将编码为application/x-www-form-urlencoded格式,同时将data键应答的值(一个JSON字符串)作为表单字段值发送。这样就完美匹配了FedEx API的期望格式。处理API响应其成功发送请求后,API会返回一个JSON格式的响应。
在PHP中,可以使用json_decode()函数将其转换为PHP备份或对象进行处理:$responseData = json_decode($response-gt;body, true); // true表示返回关联队列//获取所需信息$fedex_status = $responseData['TrackPackagesResponse']['packageList'][0]['keyStatus'];$fedex_details = $responseData['TrackPackagesResponse']['packageList'][0]['statusWithDetails'];$delivery_date = $responseData['TrackPackagesResponse']['packageList'][0]['displayActDeliveryDt'];$delivery_time = $responseData['TrackPackagesResponse']['packageList'][0]['displayActDeliveryTm'];登录后复制注意事项与最佳实践
在进行API集成时,除了考虑正确构造的请求外,还需要以下几点:API稳定性: 外部API可能会更新或改变其请求/响应格式。定期测试您的集成代码是必需的。错误处理:不断检查HTTP响应状态码(例如200表示成功)和API返回的错误信息(如CALError)。这有助于诊断问题。安全性:API需要认证(尽管FedEx此接口公共需要),请安心管理API敏捷,避免硬编码或将其引入到公共仓库中。依赖管理:使用 Composer 管理 PHP 库(如请求),确保依赖项的正确安装和版本控制。日志记录:在生产环境中,记录 API 请求和响应的详细信息,用于调试和监控关键。性能优化:对于高度调用,考虑转换缓存 API 响应或使用异步请求。总结
将 Python 的请求库请求逻辑为 PHP 时,核心在于理解目标 API 所需的请求体格式。Python requests.post(url, data=...)默认发送application/x-www-form-urlencoded,即使data字典中的某个值是JSON字符串,它也被作为普通表单字段值处理。在PHP中,通过对特定字段进行json_encode,并让HTTP客户端库(如Requests)自动处理编码表单,可以有效地模拟这种行为。将整个请求体不加区分地编码为JSON并设置错误的Content-Type头,是成功进行跨语言API集成避免的关键。
以上就是PHP与Python网络请求转换:FedEx包裹追踪API的正确姿势的详细内容,更多请关注乐哥常识网其他相关文章!