Read the directory

  • Building service consumers
  • Install json RPC dependencies
  • Install the JSON RPC client
  • The server configuration
  • Write business code
  • Write a service consumer class
  • Consumer configuration
  • Configuration UserServiceInterface
  • Write a UserController
  • Postman test
  • Automatic configuration of service consumers
  • Configuration optimization
  • Unified result processing

As we said, a service provider can provide a variety of services, it can interact with a database; A service consumer is a purely consuming service that requires only remote access to the service provider.

Let’s build the consumer module step by step.

The source code has been uploaded to github, github.com/bailangzhan…

1. Build service consumers

Select N to install all components except for time zone Settings.

composer create-project hyperf/hyperf-skeleton shop_consumer_user 
Creating a "hyperf/hyperf-skeleton" project at "./shop_consumer_user"
Installing hyperf/hyperf-skeleton (v2.2.1)
  - Installing hyperf/hyperf-skeleton (v2.2.1): Extracting archive
Created project in /data/web/test/hyperf-rpc/shop_consumer_user
> @php -r "file_exists('.env') || copy('.env.example', '.env');"
> Installer\Script::install
Setting up optional packages
Setup data and cache dir
Removing installer development dependencies
  What time zone do you want to setup ?
  [n] Default time zone for php.ini
Make your selection or type a time zone name, like Asia/Shanghai (n):
Asia/Shanghai
  Do you want to use Database (MySQL Client) ?
  [y] yes
  [n] None of the above
  Make your selection or type a composer package name and version (yes): n
  Do you want to use Redis Client ?
  [y] yes
  [n] None of the above
  Make your selection or type a composer package name and version (yes): n
  Which RPC protocol do you want to use ?
  [1] JSON RPC with Service Governance
  [2] JSON RPC
  [3] gRPC
  [n] None of the above
  Make your selection or type a composer package name and version (n): n
  Which config center do you want to use ?
  [1] Apollo
  [2] Aliyun ACM
  [3] ETCD
  [4] Nacos
  [n] None of the above
  Make your selection or type a composer package name and version (n): n
  Do you want to use hyperf/constants component ?
  [y] yes
  [n] None of the above
  Make your selection (n): n
  Do you want to use hyperf/async-queue component ? (A simple redis queue component)
  [y] yes
  [n] None of the above
  Make your selection or type a composer package name and version (n): n
  Do you want to use hyperf/amqp component ?
  [y] yes
  [n] None of the above
  Make your selection or type a composer package name and version (n): n
  Do you want to use hyperf/model-cache component ?
  [y] yes
  [n] None of the above
  Make your selection or type a composer package name and version (n): n
  Do you want to use hyperf/elasticsearch component ?
  [y] yes
  [n] None of the above
  Make your selection or type a composer package name and version (n): n
  Do you want to use hyperf/tracer component ? (An open tracing protocol component, adapte with Zipkin etc.)
  [y] yes
  [n] None of the above
  Make your selection or type a composer package name and version (n): n
Copy the code

2. Install json RPC dependencies

cd shop_consumer_user
composer require hyperf/json-rpc
Copy the code

3. Install the JSON RPC client

Shop_consumer_user does not need to provide external services, so we only install the client and do not need to install the Hyperf/RPC-Server component

composer require hyperf/rpc-client
Copy the code

4. Server configuration

The default configuration of the server is good, port 9501 provides HTTP service, do not need to change

'the servers = > [[' name' = > 'HTTP' and 'type' = > Server: : SERVER_HTTP, 'host' = > '0.0.0.0' and 'port' = > 9501, 'sock_type' => SWOOLE_SOCK_TCP, 'callbacks' => [ Event::ON_REQUEST => [Hyperf\HttpServer\Server::class, 'onRequest'], ],]],Copy the code

5. Write business code

5-1. Write the service consumer class

Create the JsonRpc directory under app and write the userService. PHP and UserServiceInterface

【 UserServiceInterface. PHP 】 <? php namespace App\JsonRpc; interface UserServiceInterface { public function createUser(string $name, int $gender); public function getUserInfo(int $id); } <span class=" readactor-invisible -space"> </span>【 userservice.php 】 <? php namespace App\JsonRpc; use Hyperf\RpcClient\AbstractServiceClient; Class UserService extends AbstractServiceClient implements UserServiceInterface {/** * defines the service name of the corresponding service provider * @var string */ protected $serviceName = 'UserService'; @var string */ protected $protocol = 'jsonrpc-http'; /** * @param string $name * @param int $gender * @return mixed */ public function createUser(string $name, int $gender) { return $this->__request(__FUNCTION__, compact('name', 'gender')); } /** * @param int $id * @return mixed */ public function getUserInfo(int $id) { return $this->__request(__FUNCTION__, compact('id')); }}Copy the code

Hyperf’s official Hyperf/Rpc-client component already implements RPC remote calls for us, so we just need to configure the service consumer to tell HyperF which node to call from which port.

5-2. Consumer configuration

Defined in the config/autoload/services. The PHP consumers are as follows: (no services. The PHP files can create)

<? PHP return ['consumers' => [[$serviceName 'name' => 'UserService', // directly consume the specified node, Through the following nodes parameters to configure the service provider's node information 'nodes' = > [[' host' = > '127.0.0.1', 'port' = > 9600],] and]]];Copy the code

5-3. Configure UserServiceInterface

In order to easy to inject UserServiceInterface, we in the config/autoload/dependencies. Define UserServiceInterface and UserService relationships within the PHP is as follows:

App\JsonRpc\UserServiceInterface::class => App\JsonRpc\UserService::class,
Copy the code

5-4. Write UserController to achieve the interface call of obtaining users and creating users

The app/Controller/UserController. PHP 】 <? php declare(strict_types=1); namespace App\Controller; use App\JsonRpc\UserServiceInterface; use Hyperf\Di\Annotation\Inject; use Hyperf\HttpServer\Annotation\AutoController; /** * Class UserController * @package App\Controller * @AutoController() */ class UserController extends AbstractController { /** * @Inject() * @var UserServiceInterface */ private $userServiceClient; public function createUser() { $name = (string) $this->request->input('name', ''); $gender = (int) $this->request->input('gender', 0); return $this->userServiceClient->createUser($name, $gender); } public function getUserInfo() { $id = (int) $this->request->input('id'); return $this->userServiceClient->getUserInfo($id); }}Copy the code

6. Postman access test

When starting the shop_consumer_user project, make sure shop_PROVIDer_User is also started, otherwise the request will fail.

7. Automatic configuration of service consumers

As you may have noticed, the methods of the app\JsonRpc\UserService class have no practical meaning, just build parameters that initiate the request and return the response result. Hyperf supports the auto-configuration service consumer agent class (auto-configuration is not currently supported by producers).

Automatic configuration is very simple, just add the service configuration to the Consumer configuration item as follows:

Return ['consumers' => [[// $serviceName 'name' => 'UserService', // Service interface name, optional, default value is the value configured by name, If name is directly defined as an interface class, this configuration can be ignored. / / if the name is the string is need to configure the service corresponding to the interface class 'service' = > \ App \ JsonRpc \ UserServiceInterface: : class, / / the specified node consumption directly, Through the following nodes parameters to configure the service provider's node information 'nodes' = > [[' host' = > '127.0.0.1', 'port' = > 9600],] and]]];Copy the code

Now we do two things to test whether the consumer goes through the auto-configuration or manually created UserService

  1. The config/autoload/dependencies. PHP defined within UserServiceInterface relationship with UserService shielding
  2. Print the point data test in the App\JsonRpc\UserService::getUserInfo() method
A GET request to http://127.0.0.1:9501/user/getUserInfo? If id=2 then the console does not have any output and goes to auto-configured consumerCopy the code

In turn,

  1. We put the config/autoload/dependencies. Define UserServiceInterface and UserService relationships within the PHP
  2. The config/autoload/services. The service configuration items blocking a consumers within the PHP file
A GET request to http://127.0.0.1:9501/user/getUserInfo? Id =2 string(36) "App\JsonRpc\UserService::getUserInfo" Go to the manually created consumerCopy the code

In no special case, we will only configure the subsequent consumer, not manually create it, because there is no need to create it.

8. Configuration optimization

We noticed that the config/autoload/services. The consumers within the PHP file configuration, a service is a configuration, service consumers need to spend many, so we write here, it is necessary to optimize it’s written reference website:

/ / service definition $consumerServices = [' UserService = > \ App \ JsonRpc \ UserServiceInterface: : class,]; return [ 'consumers' => value(function () use ($consumerServices) { $consumers = [];  foreach ($consumerServices as $name => $interface) { $consumers[] = [ 'name' => $name, 'service' => $interface, 'nodes' = > [[' host' = > '127.0.0.1' and 'port' = > 9600],],];} return $consumers;}),];Copy the code

In this way, we only need to add a new service to the array $consumerServices each time.

Finally, let’s look at a bigger problem.

The consumer gets the result, which is both a string and an object, and often directly Internal Server Error. The inconsistency of data format is very unfavorable for front-end partners to parse.

Unified result processing

In order to standardize, we have developed a simple standard to uniformly return data formats with code, message and data. If you are interested, you can study how to solve this problem first. We will continue in the next section.