惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

H
Heimdal Security Blog
P
Privacy International News Feed
S
Schneier on Security
P
Proofpoint News Feed
L
Lohrmann on Cybersecurity
Spread Privacy
Spread Privacy
P
Privacy & Cybersecurity Law Blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Scott Helme
Scott Helme
K
Kaspersky official blog
大猫的无限游戏
大猫的无限游戏
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
aimingoo的专栏
aimingoo的专栏
Simon Willison's Weblog
Simon Willison's Weblog
S
Securelist
Help Net Security
Help Net Security
B
Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Security Archives - TechRepublic
Security Archives - TechRepublic
云风的 BLOG
云风的 BLOG
The GitHub Blog
The GitHub Blog
N
News and Events Feed by Topic
Hacker News: Ask HN
Hacker News: Ask HN
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
M
MIT News - Artificial intelligence
雷峰网
雷峰网
博客园 - 司徒正美
V
V2EX
AWS News Blog
AWS News Blog
Know Your Adversary
Know Your Adversary
N
News | PayPal Newsroom
T
Tor Project blog
Cisco Talos Blog
Cisco Talos Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
PCI Perspectives
PCI Perspectives
Google DeepMind News
Google DeepMind News
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
U
Unit 42
C
Cybersecurity and Infrastructure Security Agency CISA
P
Palo Alto Networks Blog
G
Google Developers Blog
T
Threat Research - Cisco Blogs
博客园 - Franky
I
InfoQ
D
DataBreaches.Net
爱范儿
爱范儿
Y
Y Combinator Blog
博客园 - 叶小钗
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报

青空之蓝

[青空之蓝-2023] - 色彩 | 青空之蓝 [青空之蓝-2022] - 平静 | 青空之蓝 [青空之蓝-2021] - 远望 | 青空之蓝 浅谈垃圾回收 | 青空之蓝 浅谈泛型擦除 | 青空之蓝 浅谈单点登录 | 青空之蓝 使用 Kotlin 编写 Spring 测试 | 青空之蓝 设计模式系列文章 | 青空之蓝 从零实现一个 Java 微框架 - IoC | 青空之蓝 从零实现一个 Java 微框架 - 前言 | 青空之蓝 浅谈 JVM:类加载 | 青空之蓝 浅谈 IO | 青空之蓝 浅谈并发:synchronized & ReentrantLock | 青空之蓝 浅谈并发:CAS & AQS | 青空之蓝 浅谈并发:ThreadLocal | 青空之蓝 浅谈并发:三大特性 | 青空之蓝 浅谈组合注解 & 注解别名 | 青空之蓝 [青空之蓝-2020]-迷茫 | 青空之蓝 Java 系列文章 | 青空之蓝 HTTP 系列文章 | 青空之蓝 浅谈 EatWhatYouKill | 青空之蓝 浅谈可扩展线程池 | 青空之蓝 聊聊写框架 | 青空之蓝 聊聊现状-[2020-09] | 青空之蓝 浅谈并发:锁 | 青空之蓝 浅谈并发:基础 | 青空之蓝 浅谈缓存 | 青空之蓝 无须定义类,Spring 快速注入 Json 参数 | 青空之蓝 浅谈 Proxy 和 Aop | 青空之蓝 从零实现一个 PHP 微框架 - 初始化请求 | 青空之蓝 为 Vue3 添加一个简单的 Store | 青空之蓝 从零实现一个 PHP 微框架 - 服务提供者 | 青空之蓝 WSL2 踩坑记录 | 青空之蓝 浅谈浏览器Event Loop [更新] | 青空之蓝 从零实现一个 PHP 微框架 - Bootstrap 启动加载 | 青空之蓝 从零实现一个 PHP 微框架 - IoC 容器 | 青空之蓝 从零实现一个 PHP 微框架 - PSR & Composer | 青空之蓝 从零实现一个 PHP 微框架 - 前言 | 青空之蓝 MVVM 简单实现 | 青空之蓝 浅谈 DI 和 IoC | 青空之蓝 告别 Windows 终端的难看难用,打造好用的 PowerShell | 青空之蓝 VSCode Java输出中文乱码问题解决[更新] | 青空之蓝 浅谈浏览器渲染 | 青空之蓝 Vue-Cli@2 项目迁移日志 | 青空之蓝 Laragon & Scoop 集成踩坑记录 | 青空之蓝 「一行代码」优雅管理 Windows 软件 | 青空之蓝 [青空之蓝-2019]-年度总结 | 青空之蓝 为Vue添加简单的Store | 青空之蓝 为React添加简单的Store | 青空之蓝 为Vuex添加同步Action | 青空之蓝 浅谈B+树 | 青空之蓝 浅谈跳表 | 青空之蓝 浅谈数据库索引 | 青空之蓝 MySQL事务隔离 | 青空之蓝 算法复杂度分析(1) | 青空之蓝 一年来的经验总结 | 青空之蓝 Acrylic - VSCode Extension | 青空之蓝 ace编辑器设置惯性滚动 | 青空之蓝 Java二叉树实现 | 青空之蓝 Java图实现 | 青空之蓝 为apt方式安装的nginx重新编译增加WebDAV | 青空之蓝 XK-Editor - 一个支持富文本和Markdown的编辑器 | 青空之蓝 JS生成列表树 | 青空之蓝 Laravel生成目录树 | 青空之蓝 XK-Note - 集各种神奇功能的云笔记 | 青空之蓝 PHP GD生成验证码 | 青空之蓝 PHP GD图片处理[转换格式-水印-缩略图] | 青空之蓝 Origami - 简洁轻快的WordPress主题 | 青空之蓝 为WordPress启用WorkBox | 青空之蓝 [青空之蓝-2018]-年度总结 | 青空之蓝 VSCode Java手动导入jar和源码包 | 青空之蓝 Windows IP变化自动发送邮件 | 青空之蓝 C链表实现重制版 | 青空之蓝 C 结构体的定义和使用 | 青空之蓝 图的搜索(遍历) - BFS & DFS | 青空之蓝 Java链表实现 | 青空之蓝 C 快速排序 | 青空之蓝 C 插入排序 | 青空之蓝 C 归并排序 | 青空之蓝 C语言链表实现 | 青空之蓝 VSCode配置Java调试环境[Windows] | 青空之蓝 C 选择排序 | 青空之蓝 C 冒泡排序 | 青空之蓝 VSCode配置PHP调试环境[Windows] | 青空之蓝 VSCode配置C/C++ GDB调试环境[Windows] | 青空之蓝 WordPress友情链接模板 | 青空之蓝 Intel Optane 傲腾内存体验 | 青空之蓝 Mysql双机热备实战 | 青空之蓝 博客一年记录 | 青空之蓝 为WordPress启用Service Worker | 青空之蓝 Bing每日一图API | 青空之蓝 iframe延迟加载 | 青空之蓝 写在2018年高考前 | 青空之蓝 The Fox主题汉化分享 | 青空之蓝 [青空之蓝-2017]-崭新 | 青空之蓝 本博客评论规则 | 青空之蓝 世界,您好! | 青空之蓝
中间件实现 [PHP] | 青空之蓝
Otstar Lin · 2020-03-29 · via 青空之蓝

中间件是什么?

要实现中间件,首先就需要知道中间件是什么。中间件是很多 PHP 框架中都提供的功能,中间件提供了一种方便的机制过滤进入应用程序的 HTTP 请求。这么说可能会比较抽象,我们就举个具体的例子吧。

比如某个商城应用,当用户把商品加入购物车的时候和购买的时候,我们需要验证用户是否已经登录,传统的方式是在执行每个业务之前判断是否登录,如下演示代码:

<?php
function addToCart() {
    if (!isLogin()) {
        return "用户未登录";
    }
    // ... 添加到购物车操作
    return "添加到购物车成功";
}

function buy() {
    if (!isLogin()) {
        return "用户未登录";
    }
    // ... 购买操作
    return "购买成功";
}

function entry() {
    // addToCart or buy
}
<?php
function addToCart() {
    if (!isLogin()) {
        return "用户未登录";
    }
    // ... 添加到购物车操作
    return "添加到购物车成功";
}

function buy() {
    if (!isLogin()) {
        return "用户未登录";
    }
    // ... 购买操作
    return "购买成功";
}

function entry() {
    // addToCart or buy
}

可以看到,当需要验证用户的时候就需要写重复的代码,那么我们为什么不把验证的部分另外抽出来呢,如下:

<?php
function addToCart() {
    // ... 添加到购物车操作
    return "添加到购物车成功";
}

function buy() {
    // ... 购买操作
    return "购买成功";
}

function entry() {
    if (!isLogin()) {
        return "用户未登录";
    }
    // addToCart or buy
}
<?php
function addToCart() {
    // ... 添加到购物车操作
    return "添加到购物车成功";
}

function buy() {
    // ... 购买操作
    return "购买成功";
}

function entry() {
    if (!isLogin()) {
        return "用户未登录";
    }
    // addToCart or buy
}

可以看到这样遇到相同需要验证的时候就不再需要写重复的验证代码了,而这种做法其实就是中间件的思想,抽离出来的验证登录就是一个中间件。有了中间件我们就可以这些操作,比如权限验证、CSRF 验证等等都写在中间件里,然后通过使用不同的中间件组合不仅能够实现需求还降低了代码的耦合度。

中间件

比较常见的中间件模型有两种,一种是洋葱模型,一种是切面模型,其实这两个可以看成是一种,不过分开来比较好理解 2333。

左:洋葱模型,右:切面模型

这两个图看起来是不是有点吓人,切面模型其实还比较好理解,洋葱模型看起来就有点懵了,是不是有点像函数的嵌套调用 Middleware2(Middleware1(App()))?其实这并不是这样的,因为函数的嵌套调用是先执行内层的函数,然后才会执行外层的函数。若你经常使用回调函数方式的编程,那么你就能发现这其实像闭包嵌套:

<?php
function middleware2() {
    echo "Start Middleware2\n";
    middleware1();
    echo "End Middleware2\n";
}

function middleware1() {
    echo "Start Middleware1\n";
    app();
    echo "End Middleware1\n";
}

function app() {
    echo "App\n";
}

function entry() {
    middleware2();
}

entry();

// Start Middleware2
// Start Middleware1
// App
// End Middleware1
// End Middleware2
<?php
function middleware2() {
    echo "Start Middleware2\n";
    middleware1();
    echo "End Middleware2\n";
}

function middleware1() {
    echo "Start Middleware1\n";
    app();
    echo "End Middleware1\n";
}

function app() {
    echo "App\n";
}

function entry() {
    middleware2();
}

entry();

// Start Middleware2
// Start Middleware1
// App
// End Middleware1
// End Middleware2

优雅的实现

可以看到上面的实现是写死的,如果要增加或者动态使用中间件就极为麻烦,所以我们需要对其进行改造,改造成可以动态调用的中间件。这也是我在 XK-PHP 中使用的方法。

<?php
// 中间件
class Authenticate
{
    public function handle($request, Closure $next)
    {
        echo "Start 登录\n";
        $response = $next($request);
        echo "End 登录\n";
        return $response;
    }
}

class SimpleMiddleware
{
    public function handle($request, Closure $next)
    {
        echo "Start SimpleMiddleware\n";
        $response = $next($request);
        echo "End SimpleMiddleware\n";
        return $response;
    }
}

// App
class App
{
    public function run($request)
    {
        return "App-$request\n";
    }
}

// 中间件处理器
$middlewares = [
    Authenticate::class,
    SimpleMiddleware::class
];

$next = function ($request) {
    return (new App)->run($request);
};

foreach ($middlewares as $middleware) {
    $next = function ($request) use ($next, $middleware) {
        return (new $middleware)->handle($request, $next);
    };
}

$response = $next("request");

echo $response;

// Start SimpleMiddleware
// Start 登录
// End 登录
// End SimpleMiddleware
// App-request
<?php
// 中间件
class Authenticate
{
    public function handle($request, Closure $next)
    {
        echo "Start 登录\n";
        $response = $next($request);
        echo "End 登录\n";
        return $response;
    }
}

class SimpleMiddleware
{
    public function handle($request, Closure $next)
    {
        echo "Start SimpleMiddleware\n";
        $response = $next($request);
        echo "End SimpleMiddleware\n";
        return $response;
    }
}

// App
class App
{
    public function run($request)
    {
        return "App-$request\n";
    }
}

// 中间件处理器
$middlewares = [
    Authenticate::class,
    SimpleMiddleware::class
];

$next = function ($request) {
    return (new App)->run($request);
};

foreach ($middlewares as $middleware) {
    $next = function ($request) use ($next, $middleware) {
        return (new $middleware)->handle($request, $next);
    };
}

$response = $next("request");

echo $response;

// Start SimpleMiddleware
// Start 登录
// End 登录
// End SimpleMiddleware
// App-request

这段代码如果不熟悉闭包的看起来可能有点懵,不过仔细理解下就很简单了。

在中间件的类中有一个 handle 函数用于处理请求或响应,外部向该函数传入了一个 $next 闭包,这个闭包其实就是后续的 中间件App 的打包成的 闭包。通过循环就可以不断的组成新的闭包,合并所有中间件后就可以执行了,此时只需要执行最终的闭包,最终的闭包会不断的嵌套调用 $next 闭包,直到最后的 App 其实就是个递归的过程。不过我这里干讲也无法讲清楚,最好还是要利用 IDE 一步一步调试才能更好的理解。

更优雅的实现

第二个实现虽然已经很好了,但是并不符合 PSR-15 的标准,所以如果要更优雅的方式来实现中间件的话需要按照 PSR-15 的标准来实现,这样就可以复用 PSR-15 的中间件,并且也符合 PSR-7 消息接口的规范。具体的代码这里就不贴了,请移步 Github 查看。

中间件实现 [PHP]

https://blog.ixk.me/post/middleware-implementation-with-php
  • 许可协议

    BY-NC-SA

  • 本文作者

    Otstar Lin

  • 发布于

    2020/03/29

转载或引用本文时请遵守许可协议,注明出处、不得用于商业用途!

浅谈 DI 和 IoC告别 Windows 终端的难看难用,打造好用的 PowerShell

HomeGitHubStatus

Copyright © 2017-2026 Otstar Lin

Theme Coline by Otstar LinPowered by Next.js