某国企最近提了一个需求,在内网网站发布新闻的时候,需要同步到外网网站一份。这本来是一个很简单的需求,但考虑到新闻中包含的诸多图片,以及内网发布新闻时图片上传与发布操作并非同步进行,因此采用了转码的方式。即不管用户上传多少张图片,只在用户点击发布时获取到所有图片的绝对路径,并转为base64格式。在服务器端接收到内网发布的数据时,对图片资源可进行转码保存或直接使用。
但是问题发生在代码本地测试没问题,传到内网服务器后,发现内网发布新闻时,外网返回数据为空。以下是排查步骤。
1、鉴于内网服务器POST外网操作采用的是PHP的CURL方式,首先检查了PHP的扩展安装及开启情况。
2、考虑是否是CURL方法有误。这种情况多发生在header头与发送数据body不一致的时候,会导致接收端接收不到发送的数据。在排查的过程中除了我们自己写的curl请求方法之外,也可以多尝试一下其他网友的方法。有时候一个参数之差可能就需要排查老半天时间。非常耽误时间。
附赠:CURL发送网络请求方法一个,支持GET、POST及debug
- /**
- * CURL请求
- * @param $url 请求url地址
- * @param $method 请求方法 get post
- * @param null $postfields post数据数组
- * @param array $headers 请求header信息
- * @param bool|false $debug 调试开启 默认false
- * @return mixed
- */
- function httpRequest($url, $method, $postfields = null, $headers = array(), $debug = false) {
- $method = strtoupper($method);
- $ci = curl_init();
- /* Curl settings */
- curl_setopt($ci, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
- curl_setopt($ci, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 6.2; WOW64; rv:34.0) Gecko/20100101 Firefox/34.0");
- curl_setopt($ci, CURLOPT_CONNECTTIMEOUT, 60); /* 在发起连接前等待的时间,如果设置为0,则无限等待 */
- curl_setopt($ci, CURLOPT_TIMEOUT, 7); /* 设置cURL允许执行的最长秒数 */
- curl_setopt($ci, CURLOPT_RETURNTRANSFER, true);
- switch ($method) {
- case "POST":
- curl_setopt($ci, CURLOPT_POST, true);
- if (!emptyempty($postfields)) {
- $tmpdatastr = is_array($postfields) ? http_build_query($postfields) : $postfields;
- curl_setopt($ci, CURLOPT_POSTFIELDS, $tmpdatastr);
- }
- break;
- default:
- curl_setopt($ci, CURLOPT_CUSTOMREQUEST, $method); /* //设置请求方式 */
- break;
- }
- $ssl = preg_match('/^https:\/\//i',$url) ? TRUE : FALSE;
- curl_setopt($ci, CURLOPT_URL, $url);
- if($ssl){
- curl_setopt($ci, CURLOPT_SSL_VERIFYPEER, FALSE); // https请求 不验证证书和hosts
- curl_setopt($ci, CURLOPT_SSL_VERIFYHOST, FALSE); // 不从证书中检查SSL加密算法是否存在
- }
- //curl_setopt($ci, CURLOPT_HEADER, true); /*启用时会将头文件的信息作为数据流输出*/
- curl_setopt($ci, CURLOPT_FOLLOWLOCATION, 1);
- curl_setopt($ci, CURLOPT_MAXREDIRS, 2);/*指定最多的HTTP重定向的数量,这个选项是和CURLOPT_FOLLOWLOCATION一起使用的*/
- curl_setopt($ci, CURLOPT_HTTPHEADER, $headers);
- curl_setopt($ci, CURLINFO_HEADER_OUT, true);
- /*curl_setopt($ci, CURLOPT_COOKIE, $Cookiestr); * *COOKIE带过去** */
- $response = curl_exec($ci);
- $requestinfo = curl_getinfo($ci);
- $http_code = curl_getinfo($ci, CURLINFO_HTTP_CODE);
- if ($debug) {
- echo "=====post data======\r\n";
- var_dump($postfields);
- echo "=====info===== \r\n";
- print_r($requestinfo);
- echo "=====response=====\r\n";
- print_r($response);
- }
- curl_close($ci);
- return $response;
- //return array($http_code, $response,$requestinfo);
- }
3、在外网服务器上写一个简单的接口,判断GET请求或POST请求后,返回请求类型(很简单的字符串能自己识别即可)。然后用POSTman或CURL请求方法进行发送数据测试。
我在测试过程中发现一个问题就是发送空数据的时候,外网接口返回了正常的返回结果。而发送模拟真实的数据时,外网又返回空白。任何提示都没有。
最后利用上述CURL封装的请求方法,开启debug后输出了一串乱码。经过解码找到了最终的原因:外网服务器的安全软件拦截了含有"Base64"字符串的请求。关掉安全软件后,数据正常录入外网数据库。
到此整个网络问题排查结束。