11

我们的环境需要为异地服务使用出站代理。通常这不是问题。在这种使用 Twilio 的情况下,返回的额外标头会破坏客户端。

传出标头:

POST /2010-04-01/Accounts/FOO/SMS/Messages.json HTTP/1.1
Authorization: Basic FOO==
User-Agent: twilio-php/3.10.0
Host: api.twilio.com
Accept: */*
Accept-Charset: utf-8
Content-Type: application/x-www-form-urlencoded
Content-Length: 108

响应标头:

HTTP/1.0 200 Connection established

HTTP/1.1 201 Created
Server: nginx
Date: Thu, 06 Jun 2013 14:39:24 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 551
Connection: close
X-Powered-By: PHP/5.3.11

我只能假设代理正在添加额外的 HTTP 标头。

Twilio 客户端会检查:

list($head, $body) = ($parts[0] == 'HTTP/1.1 100 Continue') 

据我了解,有时或版本的 curl 会在请求中自动添加 Expect 标头,并且响应中会返回 HTTP 100,但在这种情况下它不是,并且响应是 200 已建立连接。值得添加一个空的 Expect: 或一个 Expect:bacon 并没有改变结果。

我真的不想在这里过多地破解 Twilio 客户端,而且我特别想避免只添加 || $parts[0] == 'HTTP/1.0 200 Connection established' 因为看起来很乱。

是否可以在将抑制/隐藏额外标头的请求标头中发送?或者,我没有看到忽略它的 curl 选项?

出站代理是 Linux/Squid

4

2 回答 2

15

代理问题是很多脚本都面临的问题。我可以在 Internet 上找到的首选解决方案是简单地添加以下代码行。

<?php
// cURL automatically handles Proxy rewrites, remove the "HTTP/1.0 200 Connection established" string
if (false !== stripos($response, "HTTP/1.0 200 Connection established\r\n\r\n")) {
  $response = str_ireplace("HTTP/1.0 200 Connection established\r\n\r\n", '', $response);
}
?>

现在将它添加到 twilio 客户端确实有点混乱。幸运的是,您可以使用命名空间来重新创建本机函数。请参阅以下示例。

<?php
namespace FakeCurl;

//create curl_exec function with same name, but its created in the FakeCurl namespace now.
function curl_exec($ch) {
  //execute the actual curl_exec function in the main namespace
  $response =  \curl_exec($ch);

  // cURL automatically handles Proxy rewrites, remove the "HTTP/1.0 200 Connection established" string
  if (false !== stripos($response, "HTTP/1.0 200 Connection established\r\n\r\n")) {
    $response = str_ireplace("HTTP/1.0 200 Connection established\r\n\r\n", '', $response);
  } 

  return "ADDED TO RESPONSE\r\n\r\n".$response;
}

//make a regular curl request, no alterations.

$curl = curl_init();
curl_setopt_array( $curl, array(
    CURLOPT_HEADER => true,
    CURLOPT_NOBODY => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_URL => 'http://stackoverflow.com' ) );
$response = curl_exec( $curl );
curl_close( $curl );

echo '<pre>'.$response.'</pre>';

?>

输出

ADDED TO RESPONSE

HTTP/1.1 200 OK
Cache-Control: public, max-age=11
Content-Length: 191951
Content-Type: text/html; charset=utf-8
Expires: Wed, 12 Jun 2013 07:09:02 GMT
Last-Modified: Wed, 12 Jun 2013 07:08:02 GMT
Vary: *
X-Frame-Options: SAMEORIGIN
Date: Wed, 12 Jun 2013 07:08:49 GMT

因此,要与 twilio 客户端一起使用,您需要在脚本的最顶部放置以下内容:

<?php
namespace FakeCurl;
function curl_exec($ch) {
  $response =  \curl_exec($ch);

  // cURL automatically handles Proxy rewrites, remove the "HTTP/1.0 200 Connection established" string
  if (false !== stripos($response, "HTTP/1.0 200 Connection established\r\n\r\n")) {
    $response = str_ireplace("HTTP/1.0 200 Connection established\r\n\r\n", '', $response);
  } 

  return $response;
}

include("twilio.php");
?>

如果命名空间选项由于某种原因失败,我会在 twilio 客户端之外添加一个简单的函数,例如。

<?php
function fixProxyResponse($response) {
  // cURL automatically handles Proxy rewrites, remove the "HTTP/1.0 200 Connection established" string
  if (false !== stripos($response, "HTTP/1.0 200 Connection established\r\n\r\n")) {
    $response = str_ireplace("HTTP/1.0 200 Connection established\r\n\r\n", '', $response);
  } 

  return $response;
}

然后更改 twilio 脚本TinyHttp.php并仅更改以下行 (~linenr 63)

if ($response = curl_exec($curl)) {
  $parts = explode("\r\n\r\n", $response, 3);
  list($head, $body) = ($parts[0] == 'HTTP/1.1 100 Continue')

if ($response = curl_exec($curl)) {
  $parts = explode("\r\n\r\n", fixProxyResponse($response), 3);
  list($head, $body) = ($parts[0] == 'HTTP/1.1 100 Continue')
于 2013-06-12T07:14:46.680 回答
6

一些非常晚的澄清。当您通过代理连接到 SSL/TLS 服务器时,代理会使用 HTTP CONNECT 建立隧道。这包含在RFC2817和过期的隧道规范中,而不是 RFC2616。

原始隧道规范要求代理在成功连接到服务器后向客户端返回“200 连接已建立”,这就是您所看到的。在连接变得透明并且您从服务器获得实际响应之前,这可能会跟随更多标头,然后是一个空行。所以,你得到两组标题。RFC 2817 放宽了这一点,并允许任何 2xx 响应 CONNECT 请求。

简而言之,这意味着您不能依赖于使用上面的 php 代码检测和删除单个标题行。可能不止一行,第一行可能没有 200 代码,并且可能不包含“已建立连接”字符串。您必须准备好检测两套完整的标头。

cURL 在 2004 年 7.11.1 之前删除了初始连接响应,但现在将所有内容发送回客户端。有关详细信息,请参见此处

于 2015-12-30T22:08:05.693 回答