gRPC PHP 框架

v4.0.1 2023-04-27 06:03 UTC

README

Build Status

grphp 是一个 PHP 框架,它包装了 gRPC PHP 库,以提供更流畅的 PHP 应用程序集成。

它提供了一个抽象的 gRPC 服务客户端,以及其他工具,帮助快速高效地以规模集成 gRPC 服务到 PHP 应用程序。其功能包括

  • 强大的客户端错误处理和元数据传输能力
  • 支持服务器身份验证策略,内置了支持多个密钥的基本身份验证
  • 在输出元数据中序列化错误数据,以允许在传输中进行细粒度错误处理,同时仍然保留 gRPC BadStatus 代码
  • 在响应中的客户端执行时间
  • 通过 nghttpx 支持的 H2Proxy,允许在无需 gRPC C 库的情况下进行基于 gRPC 的通信

grphp 当前支持 gRPC 1.9.0,并需要 PHP 7.4+ 才能运行。

安装

composer require bigcommerce/grphp

您需要确保满足 grpc/grpc PHP 库的要求,这包括安装 gRPC PHP 扩展(除非您正在使用 H2Proxy 策略)。

客户端

$config = new Grphp\Client\Config([
    'hostname' => 'IP_OF_SERVER:PORT',
]);
$client = new Grphp\Client(Things\ThingsClient::class, $config);

$request = new Things\GetThingReq();
$request->setId(1234);

$resp = $client->call($request, 'GetThing');
$thing = $resp->getResponse(); // Things\Thing
echo $thing->id; // 1234
echo $resp->getStatusCode(); // 0 (these are gRPC status codes)
echo $resp->getStatusDetails(); // OK

策略

grphp 具有利用可注入策略来外部通信的能力。目前,grphp 包含两种策略

  • Grpc - 此策略类将利用核心 gRPC PHP 库来向服务进行外部通信
  • H2Proxy - 此策略设置为调用一个 nghttpx 代理,通过 HTTP/1.1 进行通信,然后升级为 HTTP/2 连接,并转换为 gRPC 请求。

H2Proxy 策略

H2Proxy 策略与一个 nghttpx 服务配对,并发送升级到 HTTP/2 和 gRPC 的 HTTP/1.1 请求。它是通过发送带有 Upgrade: h2cConnection: Upgrade 标头的二进制编码的 protobuf,nghttpx 使用这些头来将连接升级为合适的 gRPC 请求来实现的。

如果您不想使用 gRPC PHP C 扩展,但仍然想获得 protobuf 合同的好处,这很有用。如果您没有安装 gRPC PHP C 扩展,grphp 将自动切换您到 H2Proxy 策略。

以下是如何使用和配置代理策略,假设我们有一个在地址 0.0.0.0 上运行的 nghttpx 服务,端口号为 3000

$proxyConfig = new Grphp\Client\Strategy\H2Proxy\Config('http://0.0.0.0:3000', 15);
$proxyStrategyFactory = new Grphp\Client\Strategy\H2Proxy\StrategyFactory($proxyConfig);
$config = new Grphp\Client\Config([
    'strategy' => $proxyStrategyFactory->build(),
]);

这设置了代理客户端也使用 15 秒的超时。此设置是按客户端可配置的,因此您可以根据服务调整这些设置 - 以及策略 -

Envoy 策略

Envoy 策略使用 Envoy 作为 gRPC 出站流量的 HTTP/1.1 桥接。它自动序列化消息并缓冲请求以处理响应尾部。有关 Envoy 桥接的更多信息,请参阅Envoy 桥接

// Connect to Envoy at 127.0.0.1:19000
$envoyConfig = new Grphp\Client\Strategy\Envoy\Config('127.0.0.1', 19000, 2);
$envoyStrategyFactory = new Grphp\Client\Strategy\Envoy\StrategyFactory($envoyConfig);
$config = new Grphp\Client\Config([
    'strategy' => $envoyStrategyFactory->build(),
]);

这设置了代理客户端也使用 2 秒的超时。此设置是按客户端可配置的,因此您可以根据服务调整这些设置 - 以及策略 -

身份验证

身份验证通过适配器完成,适配器在配置中指定。您可以传递以下之一

  • 字符串 "basic",用于基本 HTTP 身份验证
  • 现有类的字符串类名
  • 扩展 Grphp\Authentication\Base 的实例化对象

基本身份验证

grphp 支持通过请求元数据发送的基本身份验证请求。

$config = new Grphp\Client\Config([
    'hostname' => 'IP_OF_SERVER:PORT',
    'authentication' => 'basic',
    'authentication_options' => [
        'username' => 'foo',
        'password' => 'bar', // optional
    ]
]);

自定义客户端拦截器

grphp 附带一个基 Client Interceptor 类,可以扩展以提供您自己的自定义拦截器。以下是一个示例拦截器,它将一个可定制的 "X-Foo" 标头添加到所有元数据中。

<?php
use Grphp\Client\Response;
use Grphp\Client\Interceptors\Base as BaseInterceptor;

class FooHeader extends BaseInterceptor
{
    /**
     * @param callable $callback
     * @return Response
     */
    public function call(callable $callback)
    {
        // set outgoing metadata
        $this->metadata['stuff'] = ['my_thing'];
        // make the outbound call
        $response = $callback();  
        // adjust incoming metadata        
        $response->setMetadata([
            'X-Foo' => $this->options['foo_value'],
        ]);
        return $response;
    }
}

请注意,您必须确保执行调用的回调。

然后,您将其正常添加。

$i = new FooHeader(['foo_value' => 'bar']);
$client->addInterceptor($i);

拦截器按照它们被添加的顺序运行,逐个包装。

重试拦截器

可以使用 Retry 拦截器为给定的 gRPC 错误状态代码启用重试。

use Grphp\Client\Interceptors\Retry;

$client->addInterceptor(new Retry(['max_retries' => 3]));

可以通过将选项数组传递给构造函数来自定义重试行为。以下选项可用:

错误处理

gRPC 倾向于通过状态(BadStatus)代码处理错误;然而,这些代码并未返回很多有关字段特定错误、应用程序代码或调试信息的信息。grphp 提供了一种从响应元数据中读取数据的方法,这些数据存储在 error-internal-bin 键中(可通过 error_metadata_key 配置选项进行配置)。

假设我们有一个具有附加数据的方法的服务,您可以像这样访问它

try {
    $resp = $client->call($request, 'GetErroringMethod');
    
} catch (\Grphp\Client\Error $e) {
    $trailer = $e->getTrailer();
    var_dump($trailer); // ['message' => 'Foo']
}

默认情况下,数据的反序列化器为 JSON;创建自己的反序列化器相当简单,例如,将错误头序列化为二进制 protobuf 的反序列化器。从那里,您可以简单地设置它

class MyProtoSerializer extends Grphp\Serializers\Errors\Base
{
    public function deserialize($trailer)
    {
        $header = new \My\Proto\ErrorHeader();
        $header->mergeFromString($trailer);
        return $header;
    }
}

$config = new Grphp\Client\Config([
    'hostname' => 'IP_OF_SERVER:PORT',
    'error_serializer' => new MyProtoSerializer(),
]);

序列化器可以传递为类的字符串名称或类的实例。如果您传递字符串名称,您可以将 error_serializer_options 的关联数组传递到配置中,以提供序列化器的选项。

路线图

  • 添加 TLS 配置支持
  • 通过 FastCGI 通过边车代理实验性支持 gRPC 服务器

许可证

版权(c)2017-至今,BigCommerce Pty. Ltd. 版权所有

特此授予任何获得本软件和相关文档副本(“软件”)的人免费权利,可以在不受限制的情况下处理该软件,包括但不限于使用、复制、修改、合并、发布、分发、再许可和/或销售软件副本,并允许向软件提供者提供软件的人这样做,但受以下条件约束

上述版权声明和本许可声明应包含在软件的所有副本或实质性部分中。

软件按“原样”提供,不提供任何明示或暗示的保证,包括但不限于适销性、适用于特定目的和无侵权性保证。在任何情况下,作者或版权持有人均不对任何索赔、损害或其他责任负责,无论此类索赔、损害或其他责任是基于合同、侵权或其他方式产生,是否与软件或软件的使用或其他交易有关。