6

我正在解决一些与 POST 到远程站点有关的问题,特别是远程主机从不返回任何数据(空字符串)。

在我尝试排除其他任何问题之前,我想确保调用代码实际上是正确的。代码是:

$context = stream_context_create(array('http' => array(
    'method'        => "POST",
    'header'        => "Content-Type: application/xml",
    'timeout'       => 60.0,
    'ignore_errors' => true, # return body even if HTTP status != 200
    'content'       => $send_xml
)));

$response = trim(file_get_contents($this->bulk_service_url, false, $context));

我所有的问题都属于“标题”选项及其值,以及如何正确格式化和编写它。PHP 文档、下面的讨论甚至 stackoverflow 研究都产生了非常不一致的结果。

1) 我是否必须包含 Content-Length 标头,如果没有,PHP 会正确计算吗?文档没有包含它,但是我看到很多人手动包含它,那么它是尊重还是被 PHP 覆盖?

2)我是否必须将 header 选项作为字符串或关联数组传递?手册说字符串,大多数将其作为字符串传递,但此注释说如果 PHP 是使用 --with-curlwrappers 选项编译的,则必须将其作为数组传递。这是非常不一致的行为。

3)当作为字符串传递时,我是否必须包含终止\r\n字符?尤其是在仅指定一个标头时。手册没有提供这样的示例,手册页上的第一个评论确实包含它,第二个没有,同样,对于如何指定它没有明确的规则。PHP 会自动处理这两种情况吗?

服务器使用 PHP 5.3。

4

3 回答 3

5

您应该真正将您的标头作为数组存储在代码中,并在发送请求之前完成准备工作......

function prepareHeaders($headers) {
  $flattened = array();

  foreach ($headers as $key => $header) {
    if (is_int($key)) {
      $flattened[] = $header;
    } else {
      $flattened[] = $key.': '.$header;
    }
  }

  return implode("\r\n", $flattened);
}

$headers = array(
  'Content-Type' => 'application/xml',
  'ContentLength' => $dl,
);

$context = stream_context_create(array('http' => array(
  'method'        => "POST",
  'header'        => prepareHeaders($headers),
  'timeout'       => 60.0,
  'ignore_errors' => true,
  'content'       => $send_xml
)));

$response = trim(file_get_contents($url, FALSE, $context));
于 2014-12-19T09:36:34.067 回答
2

准备上下文尝试添加:

  1. ContentLength: {here_calculated_length} 在 'header' 键前面带有 \r\n
  2. 'header' 键末尾的“\r\n”。

所以它应该看起来像:

$dl = strlen($send_xml);//YOUR_DATA_LENGTH
$context = stream_context_create(array('http' => array(
            'method'        => "POST",
            'header'        => "Content-Type: application/xml\r\nContentLength: $dl\r\n",
            'timeout'       => 60.0,
            'ignore_errors' => true, # return body even if HTTP status != 200
            'content'       => $send_xml
        )));
于 2013-12-20T18:44:45.363 回答
1

只是对@doublejosh 的建议进行了一点改进,以防它对某人有所帮助:(
使用数组表示法和单线 lambda 函数)

    $headers = [
      'Content-Type'   => 'application/xml',
      'Content-Length' => strlen($send_xml)
    ];
    
    $context = stream_context_create(['http' => [
        'method'       => "POST",
        'header'       => array_map(function ($h, $v) {return "$h: $v";}, array_keys($headers), $headers),
        'timeout'      => 60.0,
        'ignore_errors'=> true, 
        'content'      => $send_xml
        ]
    ]);
于 2017-11-28T15:18:27.860 回答