虚拟场景:
假设有一们平台,需要用某种道具兑换话费吧,那么话费一般是第三方服务,怎么样保证这上兑换流程安全不损失呢?
逻辑很简单:用户(消费道具)-》平台(扣除道具)-》话费平台(充值话费)话费平台不管成功或者是失败都要响应平台,以做下一步逻辑处理,如果失败,道具要返回给用户。
小明拿到需求之后很快的就实现了,跑了一段时间也没出什么问题,可是突然最近的一个月和平台兑账,差了100多万?
但就是这么简单的一个逻辑,很可能造成严重的经济损失。
小明同学实例代码如下:
//话费充值平台url
$url = "http://localhost:8080/test1.php";
$ch = curl_init($url);
curl_setopt($ch,CURLOPT_CONNECTTIMEOUT,3);
curl_setopt($ch,CURLOPT_TIMEOUT,5);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,TRUE);
curl_setopt($ch,CURLOPT_POSTFIELDS,"a=1&c=2");
$response = curl_exec($ch);
curl_close($ch);
//假设这样是话费平台成功的标识
if($response && $response['status']==1){
//修改订单为成功状态
....
//返回成功
} else {
//修改订单为失败状态
//给玩家退道具
//返回失败
}
以上猛的一看,确实没什么问题,但是忽略了网络异常的情况,或者第三方服务异常的情况产生,就是这么一个逻辑处理,造成了不可挽回的损失。
问题出现在哪里呢?
如果请求超时呢,如果请求超时如何确定第三方服务是否收到你的请求了呢,或者收到了你的请求没有及时响应呢?如果出现这种情况就判断为失败就给玩家退了已消耗的道具,就杯具 了。
对于开发者来说,一定要严格判断各种请求状态码,最起码要判断在规则的时间内响应状态再去决定是否真正要给用户退道具
对于上面的代码,我们需要加多一层处理,在curl_time_out之后的逻辑处理,如果curl在响应时间内未响应,要及时获得curl的错误码和错误消息,或者用curl_getinfo获得连接句柄的信息:
Array
(
[url] => http://localhost:8080/test1.php
[content_type] =>
[http_code] => 0
[header_size] => 0
[request_size] => 138
[filetime] => -1
[ssl_verify_result] => 0
[redirect_count] => 0
[total_time] => 5.008
[namelookup_time] => 1.0E-6
[connect_time] => 1.0E-6
[pretransfer_time] => 1.0E-6
[size_upload] => 7
[size_download] => 0
[speed_download] => 0
[speed_upload] => 1
[download_content_length] => -1
[upload_content_length] => 7
[starttransfer_time] => 0
[redirect_time] => 0
[redirect_url] =>
[primary_ip] => ::1
[certinfo] => Array
(
)
[primary_port] => 8080
[local_ip] => ::1
[local_port] => 61197
)
上面是请求超时响应的curl句柄信息,它的响应码http_code不是200,所在在现实的场景中要做http_code!=200时的逻辑判断,如果不是正常的响应,一定不要给用户做退款操作!!!!!