《细说PHP》第四版 样章 第23章 自定义PHP接口规范 8

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:https://blog.csdn.net/ITXDL123/article/details/100651030

23.5.2 架构详解

本例的实现最重要的就是服务层的设计,有两个配置文件config.php和api.php,其中文件config.php是全局的配置文件,用于整个程序全局需要的参数设置。可以根据程序扩展需求,在配置文件中增加新的配置选项。config.php文件的内容如下所示:

本例配置文件采用PHP常量和数组两种格式,直接加载这个文件,常量就可以在任意位置使用,数组也可以作为全局变量直接在程序中使用。这个配置文件中包含了项目根目录“S_ROOT”和程序根目录“DS”两个常量,以及一个多维数组$configs。可以通过改变数组中的元素值,配置数据库的连接信息,以及改变和客户端匹配的“token”字符串。

配置文件api.php一定要根据程序相关的规则,添加路由记录,不能是任意格式的。因为路由主程序会用这个文件中设置好的路由规则匹配当前的URL,来选择控制器去处理请求,给客户端返回响应消息。api.php添加的部分路由规则示例如下:

在WebAPI中,控制器(Controller)是用来操作HTTP请求的,控制器里的“action” 方法对应不同的HTTP请求。当WebAPI收到一个HTTP请求时,路由表就会将请求映射到对应的“action”方法中。路由表的定义需要根据WebAPI的访问需求,一条条自行添加。当WebAPI框架收到HTTP请求时,它会尝试从路由表的模板中匹配一个URL,如果是重复的路由规则,会使用最前面的那一条,如果不匹配将会显示给用户错误响应消息。我们注册的这个模板规则说明如下:

Ø Router 是路由类名,通过我们定义路由类的静态方法实现路由匹配和映射机制。

Ø Router::get()是路由类中定义的用户请求方法,可以是get、post、put、delete和resource中的一个。其中,resource方法默认注册了一系列用户请求的路由规则,如果是一些通用的请求操作,只使用这一个方法注册,通用的操作请求如增、删、改、查等路由策略都可以实现。其他的方法则都是一条记录对应路由的一个请求。

Ø 路由方法中第一个参数是资源名称,需要自定义这个名称,目的是用来设置不同的URL,从而定位到不同的资源。这个名称是一个字符串,例如,"/users"、"/users/{id}"、"/users/create"、"/users/{id}/edit"等,用户请求“GET http://api.itxdl.cn/v1/users/2”时,使用的就是资源"/users/{id}"。

Ø 路由方法中第二个参数是控制器的类名和操作方法。例如,“UserController”就是用户自定义的控制器类名称,如果不是使用Router类中的resource方法,而是使用单个的get或post等方法时,需要在这个参数中,控制器类名的后面使用“@”指定这个控制器中自定义的一个方法名称。这样就可以根据用户请求,映射到指定控制器的方法中了。如果是使用Router类中的resource方法,则不用“@”指定具体的方法,因为在Router类中默认注册了所有通用默认映射方法的匹配规则。

Ø 路由方法中第三个参数是可选参数,指定API的版本号,默认是V1。按RESTful API规范, API的URL都需要有版本号对应。

Ø 路由方法中第四个参数也是一个可选参数,指定一个中间件(自定义类Middleware)的方法名称,用来对用户请求API进行安全验证。这个安全验证的规则,可以通过在Middleware类中自定义方法进行验证,只需要将方法名称字符串传入这个参数即可。在默认情况下,如果不使用该参数,则不需要进行安全验证。

设计WebAPI最主要的操作就是从用户发起请求开始,到接口服务运行后再返给用户结果。请求和响应在框架中分别通过两个类实现,在request.php和response.php两个文件中声明。在request.php中声明的Response类,用来获取用户请求API的URI和参数,根据用户的动作才能通过路由定位到具体的资源位置,并映射到指定的控制器中去处理业务。request.php文件中的代码如下所示:

通过在主入口文件index.php中,直接调用Request类中的init()方法,获取用户请求的全部信息,并应用在路由等类中,使用Request类中的getMethod()方法获取用户的请求动作,通过getUri()方法获取请求的URI信息,还能通过all()方法得到一个数组,获取全部用户请求的信息。

API服务执行后,需要返给用户信息。不管是成功执行,还是在中间某个环节出现了问题,都需要给用户一个明确的响应,而且响应信息按RESTful API的规范,格式需要统一,这样方便用户接到响应信息后能进行规范的处理。response.php文件中的代码如下所示:

在Response类中只提供success()和error()两个对外调用的方法,返回的数据消息格式是相同的,使用JSON格式向用户返回数据。消息中有4个元素,“code”是响应消息的状态码,“message”是提示用户的消息,“time”是当前服务器的时间,通过时间的变化用于区分不同时间相同的两次操作,“data”是以多维数组形式返给用户的数据。当向用户响应成功的消息时,调用本类中的success()方法,主要在控制器的方法中使用。需要两个可选参数,如果调用时没有提供参数,默认返回的状态码为“0”表示成功,并返回空数据,默认提示“success”。第一个参数需要传递一个数组,作为响应给用户的数据。第二个参数可以自定义提示用户的响应消息。 当任何一个环境出现问题时,都可以调用error()方法响应给用户错误消息提示,可以在路由、中间件、控制器、数据访问模型等类中使用,也有两个可选参数,第一个参数是状态码,默认为“E001”。本类也提供了一组常见的返回状态码和对应的错误消息,用于标准的错误消息提示。如果使用的状态码在本类中已经存在,则返给用户这个状态码和这个状态码对应的错误提示消息,如果状态码在本类中不存在,可以返给用户自定义的状态码和自定义的错误消息。

公开的API可以不用进行安全验证,但非公开的API必须通过安全验证才能访问。本例通过middleware.php文件实现一个中间件环节,专门处理用户连接验证。该文件中声明一个类Middleware,在该类中每声明一个方法就是一个验证规则,在api.php文件的路由表的每条记录中,最后一个参数传入Middleware类任意一个方法名,就可以选择使用一种验证规则。本例只在Middleware中提供一个login()验证方法。middleware.php文件中的代码如下所示:

Middleware类中的login()验证方法,用来处理用户连接时的安全验证。算法和前面安全验证章节介绍的一样,通过时间戳参数、token和用户提供的应用参数,进行排序再加密处理,得到一个“key”,再和客户端通过URL传递过来的使用同样算法的“key”进行比对,如果相同则才允许连接。

WebAPI框架最核心的功能就是路由的实现,本例通过在router.php文件中声明的Router类实现了路由的功能。当WebAPI框架收到用户的HTTP请求时,它会尝试从api.php定义的路由表中匹配模板中的每条规则信息,调用中间件进行连接验证,再映射到对应的控制器方法,如果不匹配则会响应错误消息。router.php文件中的代码如下所示:

路由类Router其实只有一个对外公开的run()方法,在主入口文件index.php中,调用完Request类的init()方法,并处理完成用户请求后就可以直接调用。在run()方法中直接加载api.php导入路由表,其实在api.php中的路由表记录,每一条就是完成一次对Router类中一个方法的调用,例如Router::get()、Router::put或Router::resource等,而且这些方法的内部,又都是通过调用本类中addRouter()方法进行路由注册的。在addRouter()方法中,通过正则匹配获取用户的请求动作和资源,再调用中间件进行安全连接验证,最后通过调用本类的toAction()方法,映射到具体的控制器,以及控制器中对应的操作方法,实现整个路由过程。

WebAPI框架的入口是index.php文件,可以将它看作一个中央调度器。程序通过URL重写规则或其他方式,把所有URL导向本文件,由它调度其他代码。index.php文件中的代码如下所示:

因为index.php是整个程序的入口文件,所以会将配置文件,以及程序需要的类文件都直接加载进来,然后调用Request类中的init()方法,获取用户所有的请求参数,再通过调用Router类的run()方法,根据用户的请求完成路由机制的处理。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏程序员的成长之路

16 个超级实用的 Java 工具类

在Java中,工具类定义了一组公共方法,这篇文章将介绍Java中使用最频繁及最通用的Java工具类。

23510
来自专栏杰的记事本

SVG 图标在React项目中的优化

官方文档:https://webpack.docschina.org/loaders/url-loader/

14910
来自专栏杰的记事本

CSS实线边框渐变以及虚线边框渐变

给border-image加linear-gradient不难理解,但是如果单纯使用border-image,会发现效果是这样的:

41620
来自专栏沉默王二

关于 URL,说几个你不知道的点!

java.net.URL 类将 URL 地址进行了封装,并提供了解析 URL 地址的基本方法,比如获取 URL 的主机名和端口号。java.net.URLCon...

11120
来自专栏人工智能机器学习

CTF从入门到提升(十)文件上传

白名单和上一节讲的黑名单的区别在哪里?黑名单是未经许可非法用户禁止入内,我禁止某些人入内,大部分人是可以进去的。白名单是未经允许禁止入内,只有允许的人才能进入,...

26500
来自专栏杰的记事本

注意IE下Ajax Get缓存的问题

​ 常见的是ajax请求过一次以后,以后的相同url的get请求会存在下面这种情况:

11920
来自专栏杰的记事本

escape() VS encodeURI() VS encodeURIComponent()的区别

JavaScript中有三个可以对字符串编码的函数,分别是: escape,encodeURI,encodeURIComponent,相应3个解码函数:unes...

8110
来自专栏杰的记事本

img标签不同设备加载不同尺寸的图片的几种方法

一般来说,桌面端显示的是大尺寸的图像,文件体积较大。手机的屏幕较小,只需要小尺寸的图像,可以节省带宽,加速网页渲染。

28610
来自专栏杰的记事本

一些原生写法可以替代Jquery方法

jQuery的核心是通过各种选择器,选中DOM元素,可以用querySelectorAll方法模拟这个功能。

18320
来自专栏钻芒博客

支付宝WPAPY个人可申请当面付,创建应用获取当面付接口信息(私钥、公钥)

首先打开支付宝开放平台:https://openhome.alipay.com,在网页中心创建应用

37360

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励