这几天合作商家给了一个订单接口以供调用,于是我就使用php惯用的curl方式调用:



$url = 'http://www.someapi.com/api';

$body = '<?xml version="1.0" encoding="utf-8"?>
<returndata>
    <somexml></somexml>
</returndata>';


$result = api_notice_increment($url,$body);

echo '<pre>';print_r($result);exit;

function api_notice_increment($url, $data)
{

    $ch = curl_init();

    curl_setopt($ch, CURLOPT_HEADER,0);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_POST, 1);

    curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
    $lst['rst'] = curl_exec($ch);
    $lst['info'] = curl_getinfo($ch);
    curl_close($ch);
    return $lst;
}




可是调用时总是没有返回正常的值,总是返回500,于是我从网上寻找可以模拟http请求的工具,找到了这个:

可是我使用这个在线工具的时候:




却可以正常返回,后来我发现,我选择ContentType为text/html时就可以正常返回,而在选择为application/x-www-form-urlencoded时便发生跟我一样的相同错误,返回:


返回的HTML:
远程服务器返回错误: (500) 内部服务器错误。


所以我猜测也许问题就发生在设置的头部ContentType,于是我修改了我的代码,加入了设置header头的部分:


$url = 'http://www.someapi.com/api';

$body = '<?xml version="1.0" encoding="utf-8"?>
<returndata>
    <somexml></somexml>
</returndata>';


$result = api_notice_increment($url,$body);

echo '<pre>';print_r($result);exit;

function api_notice_increment($url, $data)
{

    $ch = curl_init();      

    <span style="background-color: rgb(255, 255, 0);">curl_setopt($ch, CURLOPT_HTTPHEADER, array("Content-Type: text/html", "Content-length: ".strlen($data))); </span>

    curl_setopt($ch, CURLOPT_HEADER,0);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_POST, 1);

    curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
    $lst['rst'] = curl_exec($ch);
    $lst['info'] = curl_getinfo($ch);
    curl_close($ch);
    return $lst;
}




于是,奇迹发生了!结果果然正常了~~~ ^_<!


我猜测,也许curl默认是对发送的内容进行了urlencode加密所以导致对方商家服务器端不能接收到正常的请求~~


其实php可以使用CURLOPT_HTTPHEADER来设置所有你想设置的头,甚至是这样伪造一个header头:


$headers = array();
    $headers[] = 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'; 
    $headers[] = 'Connection: Keep-Alive'; 
    $headers[] = 'Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3';
    $headers[] = 'Accept-Encoding: gzip, deflate';
    $headers[] = 'Host: 4pda.ru';
    $headers[] = 'User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:22.0) Gecko/20100101 Firefox/22.0';

    $ch = curl_init();      

    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);




以后当使用curl时发生了什么错误的时候,记得看看是不是header中需要调整~~~




至于具体application/x-www-form-urlencoded的意义:


application/x-www-form-urlencoded: 窗体数据被编码为名称/值对。这是标准的编码格式。 multipart/form-data: 窗体数据被编码为一条消息,页上的每个控件对应消息中的一个部分。 text/plain: 窗体数据以纯文本形式进行编码,其中不含任何控件或格式字符。
 补充
form的enctype属性为编码方式,常用有两种:application/x-www-form-urlencoded和multipart/form-data,默认为application/x-www-form-urlencoded。 当action为get时候,浏览器用x-www-form-urlencoded的编码方式把form数据转换成一个字串(name1=value1&name2=value2...),然后把这个字串append到url后面,用?分割,加载这个新的url。 当action为post时候,浏览器把form数据封装到http body中,然后发送到server。 如果没有type=file的控件,用默认的application/x-www-form-urlencoded就可以了。 但是如果有type=file的话,就要用到multipart/form-data了。浏览器会把整个表单以控件为单位分割,并为每个部分加上Content-Disposition(form-data或者file),Content-Type(默认为text/plain),name(控件name)等信息,并加上分割符(boundary)。