PHP 中的 protobuf 响应错误 "Unexpected wire type"

Error "Unexpected wire type" in a protobuf response in PHP

我正在执行对服务器的 POST 请求,服务器响应“正确”,但是当尝试调用 mergeFromString() 函数时,我收到以下错误:

Google\Protobuf\Internal\GPBDecodeException: Error occurred during parsing: Unexpected wire type. in Google\Protobuf\Internal\Message.php on line 353

我正在使用 CURL PHP:

$handle = curl_init($url);

$curl_options = [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => $body,
    CURLOPT_HEADER => true,
    CURLOPT_VERBOSE => true
];

curl_setopt_array($handle, $curl_options);

$curlResponse = curl_exec($handle);

$responseMessage = new MyMessage();
$responseMessage->mergeFromString($curlResponse);

curl_close($handle);

var_dump($curlResponse)结果如下:

╔╔eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2MjI1MTQwMTAsInVzZXJuYW1lIjoiNTM1MTAyODA2MCIsInZlcnNpb24iOiIyMTgwNiJ9.Li-bp3bIPdIrsRhuTWEWToS0ds62VCG-a2PCGaKSrigڲօ═"

在纯文本中,它应该看起来像这样:

1: 1
2: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2MjI1MTQwMTAsInVzZXJuYW1lIjoiNTM1MTAyODA2MCIsInZlcnNpb24iOiIyMTgwNiJ9.Li-bp3bIPdIrsRhuTWEWToS0ds62VCG-a2PCGaKSrig
3: 1619765852

我的响应.proto文件如下:

message MyMessage{
    // I'm only interested in property 2
    string prop = 2;
}

环境:

"protobuf-php / protobuf": "^ 0.1.3",
"google / protobuf": "^ 3.16"

但是,使用 Protoman (A Postman-like API client for protobuf-based messages) 的测试是成功的。我使用在 PHP.

中使用的相同原型文件进行了测试

在这种情况下,错误是因为字符串无效。
并且它是无效的,因为 CURL 返回的值(字符串)包括来自 HTTP 请求的所有数据,例如:

HTTP/2 200 
content-type: application/x-protobuf
date: Wed, 02 Jun 2021 23:12:37 GMT
content-length: 172

╔╔eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2MjI1MTQwMTAsInVzZXJuYW1lIjoiNTM1MTAyODA2MCIsInZlcnNpb24iOiIyMTgwNiJ9.Li-bp3bIPdIrsRhuTWEWToS0ds62VCG-a2PCGaKSrigڲօ═"

我没有注意到这一点,因为我认为这些细节是由 CURLOPT_VERBOSE => true 选项引起的。

现在,如何从 CURL 返回的值中提取正文有点复杂,在 this question 你会明白为什么。

我的解决方案如下(我重复一遍,阅读我提到的问题,也许更简单的解决方案适合您):

// I can't trust the Content-Length header (it may or may not be present).
// However, I can reliably calculate the length of the headers and use it instead.

$responseHeadersLength = 0;

$handle = curl_init($url);

$curl_options = [
    // ...
    CURLOPT_HEADERFUNCTION => function ($curl, $header) use (&$responseHeadersLength) {
            $len = strlen($header);
            $responseHeadersLength += $len;
            return $len;
    }
];

curl_setopt_array($handle, $curl_options);

$response = curl_exec($handle);

$body = trim(substr($response, $responseHeadersLength));