PSR-7与PSR-15:HTTP消息与中间件规范

好嘞,各位亲爱的程序员朋友们,大家好!我是你们的老朋友,人称“代码界的段子手”,今天咱们不聊风花雪月,就来聊聊编程界里的“标准情人”——PSR-7 和 PSR-15。

准备好了吗?系好安全带,咱们要开车啦!?

开场白:程序猿的爱情,从“标准”开始

话说,咱们程序员写代码,最怕的就是“不标准”。就像谈恋爱,你要是不按套路出牌,直接跟女神表白“我喜欢你的代码风格”,估计女神会赏你一个白眼,然后把你拉黑。?

同样的道理,在 PHP 的世界里,不同的框架、不同的库,要是各自为政,HTTP 请求和响应的格式都不一样,那简直就是一场灾难!想象一下,你写的中间件,今天能跑在 Laravel 上,明天就得重写才能跑在 Symfony 上,这得多闹心啊!?

所以,为了解决这个问题,PHP-FIG (PHP Framework Interoperability Group,PHP 框架互操作性小组) 这群大神就站了出来,制定了一系列的标准,也就是 PSR (PHP Standard Recommendation)。其中,PSR-7 和 PSR-15 就是关于 HTTP 消息和中间件的标准,它们就像编程界的“恋爱宝典”,让不同的框架和库能够和谐相处,共同构建美好的程序世界。

第一章:PSR-7——HTTP 消息的“身份证”

咱们先来说说 PSR-7,它定义了 HTTP 消息的通用接口。你可以把它想象成 HTTP 消息的“身份证”,不管你是请求 (Request) 还是响应 (Response),都得按照这个标准来。有了这个“身份证”,大家才能互相认识,才能进行交流。

1.1 核心接口:Request 和 Response

PSR-7 定义了两个核心接口:RequestInterfaceResponseInterface

  • RequestInterface 代表一个 HTTP 请求。它包含了请求的方法 (GET, POST, PUT, DELETE 等)、URI、Headers 和 Body 等信息。

  • ResponseInterface 代表一个 HTTP 响应。它包含了状态码、Headers 和 Body 等信息。

用表格来总结一下:

| 接口 | 描述 | 重要方法 |
| RequestInterface | 表示一个 HTTP 请求 | getRequestTarget()withRequestTarget($requestTarget)getMethod()withMethod($method)getUri()withUri(UriInterface $uri, $preserveHost = false)getProtocolVersion()withProtocolVersion($version)getHeaders()hasHeader($name)getHeader($name)getHeaderLine($name)withHeader($name, $value)withAddedHeader($name, $value)withoutHeader($name)getBody()withBody(StreamInterface $body) |
| ResponseInterface | 表示一个 HTTP 1.1 响应 | getStatusCode()withStatus($code, $reasonPhrase = '')getReasonPhrase()getProtocolVersion()withProtocolVersion($version)getHeaders()hasHeader($name)getHeader($name)getHeaderLine($name)withHeader($name, $value)withAddedHeader($name, $value)withoutHeader($name)getBody()withBody(StreamInterface $body) be HTTP消息体,也就是正文内容。

1.2 不可变性: “只读”的原则

PSR-7 强调不可变性 (Immutability)。这意味着,当你修改一个 HTTP 消息时,不是直接修改原来的对象,而是创建一个新的对象,新的对象包含了修改后的内容。这就像你修改一张照片,不是直接在原图上涂改,而是复制一份,在副本上进行修改。

这样做的好处是:

  • 线程安全: 在多线程环境下,可以避免并发修改导致的问题。
  • 可预测性: 你可以确信,在程序的任何地方,只要你拿到了一个 HTTP 消息对象,它的状态就不会被意外修改。
  • 易于调试: 跟踪代码时,更容易理解消息的状态变化。

1.3 使用示例:创建和修改 HTTP 消息

咱们来写个简单的例子,演示如何使用 PSR-7 创建和修改 HTTP 消息:

<?php

use NyholmPsr7Request;
use NyholmPsr7Response;
use NyholmPsr7Uri;
use NyholmPsr7Stream;

// 创建一个 Request 对象
$request = new Request(
    'GET',
    new Uri('https://example.com/api/users?page=1'),
    ['Content-Type' => 'application/json'],
    Stream::create('{"name": "John Doe"}')
);

// 获取请求方法
$method = $request->getMethod(); // 返回 "GET"

// 获取 URI
$uri = $request->getUri(); // 返回 Uri 对象,可以通过 $uri->getPath() 获取路径, $uri->getQuery() 获取查询参数

// 获取 Headers
$headers = $request->getHeaders(); // 返回一个数组,包含所有的 Headers

// 获取 Body
$body = $request->getBody(); // 返回一个 StreamInterface 对象,可以通过 $body->getContents() 获取内容

// 修改 Request
$newRequest = $request->withMethod('POST')
                      ->withUri(new Uri('https://example.com/api/users'))
                      ->withHeader('X-API-Key', '123456');

// 创建一个 Response 对象
$response = new Response(
    200,
    ['Content-Type' => 'application/json'],
    Stream::create('{"message": "User created successfully"}')
);

// 获取状态码
$statusCode = $response->getStatusCode(); // 返回 200

// 获取 Body
$body = $response->getBody(); // 返回 StreamInterface 对象,可以通过 $body->getContents() 获取内容

// 修改 Response
$newResponse = $response->withStatus(201)
                        ->withHeader('Location', '/api/users/123');

echo "Original Request Method: " . $method . PHP_EOL;
echo "New Request Method: " . $newRequest->getMethod() . PHP_EOL;

echo "Original Status Code: " . $statusCode . PHP_EOL;
echo "New Status Code: " . $newResponse->getStatusCode() . PHP_EOL;

在这个例子中,我们使用了 Nyholm/psr7 这个库来实现 PSR-7 接口。当然,你也可以使用其他的库,比如 GuzzleHttp/psr7

1.4 StreamInterface:数据的“管道”

在 PSR-7 中,StreamInterface 代表一个数据流。你可以把它想象成一个“管道”,数据可以从这个管道中读取或写入。StreamInterface 的主要作用是处理 HTTP 消息的 Body。

StreamInterface 提供了一系列的方法,用于读取、写入、定位和关闭数据流。

常用的方法包括:

  • getContents():读取整个流的内容。
  • read($length):从流中读取指定长度的数据。
  • write($string):将数据写入流中。
  • seek($offset, $whence):定位到流中的指定位置。
  • tell():返回流的当前位置。
  • eof():判断是否到达流的末尾。
  • close():关闭流。

1.5 小结:PSR-7 的重要性

PSR-7 为 HTTP 消息定义了一个统一的接口,使得不同的框架和库可以互相操作 HTTP 消息,而无需关心底层的实现细节。这大大提高了代码的互操作性和可维护性。就像咱们有了统一的身份证,不管走到哪里,都能被识别出来。

第二章:PSR-15——中间件的“红娘”

接下来,咱们再来说说 PSR-15,它定义了 HTTP 中间件的通用接口。你可以把中间件想象成一个“红娘”,它可以在 HTTP 请求到达你的应用程序之前,或者在 HTTP 响应返回给客户端之前,对请求和响应进行处理。

2.1 什么是中间件?

中间件是一种软件组件,它可以拦截 HTTP 请求和响应,并对其进行处理。中间件可以用于实现各种功能,比如:

  • 身份验证和授权: 验证用户的身份,并检查用户是否有权限访问资源。
  • 日志记录: 记录 HTTP 请求和响应的信息,用于调试和分析。
  • 缓存: 缓存 HTTP 响应,提高应用程序的性能。
  • 请求重写: 修改 HTTP 请求的 URI 或 Headers。
  • 响应压缩: 压缩 HTTP 响应,减少网络传输量。

2.2 核心接口:RequestHandlerInterface 和 MiddlewareInterface

PSR-15 定义了两个核心接口:RequestHandlerInterfaceMiddlewareInterface

  • RequestHandlerInterface 代表一个请求处理器。它负责接收一个 HTTP 请求,并返回一个 HTTP 响应。你可以把它想象成一个“最终boss”,它负责处理所有的请求,并生成最终的响应。

  • MiddlewareInterface 代表一个中间件。它负责接收一个 HTTP 请求和一个请求处理器,并返回一个 HTTP 响应。中间件可以对请求进行预处理,然后调用请求

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注