当前位置: 首页 > 后端技术 > PHP

Laravel-API实践教程

时间:2023-03-30 01:20:31 PHP

概述Laravel是一个非常流行的PHP框架,我们可以用它来快速构建一个WEB应用。现在WEB应用中经常使用前后端分离技术,所以我们经常会遇到需要使用Laravel构建API项目的情况。在提供API方面,Laravel很多地方只是提供了规范,并没有告诉我们如何实现。这样做的好处是Laravel放开了限制,大家可以根据自己的习惯使用。但是这样做也给刚接触Laravel的同学带来了一些困扰:如何更优雅的使用这个框架,有没有例子可以参考?建立这个项目是为了给大家提供一个参考。这是一个使用Laravel框架实现的API项目。该项目提供了一些常用功能的示例。本项目从头开始,重要修改部分末尾会添加commit链接,可自行查看变更记录。需要注意的是,这不是Laravel新手教程,文中很多地方都要求你了解Laravel的基础知识。Laravel官网文档如果你已经有了自己的实现,可以跳过本教程。这个项目的实现可能不会比你的实现更优雅。Laravel各个版本的实现方式还是有一些差异的。注意区分,但整体思路是一样的。安装这里使用composer安装Laravel。以下命令将安装最新版本的Laravel。本项目创建时的Laravel版本为v8.21.0composercreate-project--prefer-distlaravel/laravellaravel-api-example安装完成后需要自行配置项目,使其可以被外部访问。当你在浏览器中输入项目地址进入Laravel欢迎页面时,你就可以继续阅读了。路由在欢迎页面我们可以看到Laravel返回的信息是一个网页,也就是html代码。这个默认路由定义在routes/web.php中,我们需要删除它。commit我们所有的路由都必须定义在routes/api.php中,这是一个专门用来定义API路由的文件。当然,如果你的路由很多,你也可以在routes中定义其他的路由文件,然后在RouteServiceProvider中按照同样的方式加载它们。在RouteServiceProvider中,我们可以看到我们在routes/api.php中定义的路由默认都会以api为前缀,这对于WEB和API混合在同一个项目中是很有必要的,但是一个单独的API项目一般也会分开domain姓名。如:https://api.apihubs.cn/holiday/get所以我们需要把这个api前缀去掉或者换成其他前缀比如接口版本号v1commitinroutes/api.php默认路由是这样的requiresauthentication/user当我们使用浏览器或者postman访问时,会得到一个错误页面,主要信息是:Route[login]notdefined。我们使用ajax或者在postman的header中添加X-Requested-With:XMLHttpRequest头信息然后会得到一个JSON错误信息:{"message":"Unauthenticated."}这其实就是没有登录的原因。当你没有登录访问一个需要认证的接口,Laravel会抛出一个AuthenticationException,并且在response类Response会根据请求的header头自动响应。即如果以页面的形式调用,会跳转到登录页面,因为项目中还没有定义登录页面的路由,就会出现我们上面看到的错误。如果以接口的形式访问,会返回401状态码,返回JSON信息。但是我们是一个API项目,我们提供的只是接口地址。一会儿在接口地址返回JSON,一会儿返回一个页面,不觉得很尴尬吗?这里我们需要添加一个中间件来解决这个问题。然后在Kernel中注册这个中间件,使其全局生效。commitphpartisanmake:middlewareJsonApplication这样我们就配置好了一个JSON应用。当Laravel抛出任何异常时,无论我们如何访问它,我们总是会得到JSON响应信息。需要注意的是,我们仍然不能在路由或控制器的闭包中使用returnview($view),因为这会强制返回一个html页面响应。我们应该总是在我们的路由闭包或控制器中返回一个对象或一个数组,这两种格式将使Laravel自动为我们返回正确的JSON信息。错误码通过上面的配置,我们的应用可以一直返回JSON信息。例如,当出现异常时:如果认证失败,则返回{"message":"Unauthenticated."},http状态码为401。如果请求方法不正确,则返回{"message":"POST方法不具有http状态代码405。此路由支持。支持的方法:GET、HEAD。"message":"","exception":"SymfonyComponentHttpNettpFoundpKernelException",...}...但是这样的返回信息也存在问题:返回信息的格式不统一,JSON中的key有时会消失,以及接口调用者往往找不到以什么作为判断依据。异常信息是服务器端的敏感信息,会直接上报给用户。存在潜在的安全风险。异常信息是通过HTTP状态码抛出的,会导致很多错误。相同的HTTP状态码,比如500。业务场景定义了不同的错误码和错误信息,然后总是返回{"code":"","msg":"","data":""},会一直返回http状态码200,这里首先要介绍一个第三方库(这个库在项目中很多地方都会用到,也是本教程的核心,当然这个库的功能是仿照Java枚举)phpenum。commitcomposerrequirephpenum/phpenum这是一个枚举库,这里用来定义和管理错误代码和错误信息。错误代码的数量应该是固定的。至少一个模块下错误代码的个数是固定的。这里使用5位错误码,可以根据实际使用场景自行定义。我们在app目录下新建一个Enums目录,然后添加ErrorEnum,为不同的错误和异常定义不同的错误码。commit定义错误码后,我们还需要借助Laravel的渲染异常来渲染自定义异常类ApiException。commitphpartisanmake:exceptionApiException在上面的commit中,我们对常见的异常进行了处理,使其返回固定的错误码和错误信息,特别是对于数据校验失败,在data中返回详细的错误信息,你也可以添加一些其他的异常需要在Handler中处理。没有特别定义状态码的异常会统一返回一个未知错误,错误码为99999。这个错误码不应该出现在生产环境中。这个异常一般出现在调试阶段,需要解决。由于接口不再返回任何错误信息,我们只能通过日志排查问题。默认日志在您的本地目录中也非常强大。Laravel日志也很强大。您可以随意更改存储位置和媒体。这里我就不展开介绍了。至此,我们已经配置了统一的错误码。不管项目出现什么错误,抛出什么异常,接口返回的信息永远是{"code":"","msg":httpstatuscode200"","data":""}但是这些状态码都是在系统产生异常时返回的。如果我们想返回一个自定义的状态码怎么办?很简单,你只需要返回任意自定义状态,在代码处抛出一个自定义异常即可(不过除了controller层,其他层可能用非web方式,比如console,应该不会catchApiException,所以尽量确保在控制器中抛出ApiException)thrownewApiException(ErrorEnum::UNKNOWN_ERROR());//{"code":99999,"msg":"服务器繁忙,请稍后再试","data":""}thrownewApiException(ErrorEnum::UNKNOWN_ERROR(),'这是一个数据');//{"code":99999,"msg":"服务器繁忙,请稍后再试","data":"这是一条数据"}如果返回成功消息怎么办,方法有很多种实现这个,可以使用官方文档例子中的response宏,也可以使用helper类,也可以使用...这里我们选择Laravel的Resource,新建一个Resource类JsonResponse,在里面处理CommonLaravel对象并添加了分页处理。commit这样当我们要返回成功信息时,只需要返回这个实例即可。返回新的JsonResponse($mixed);配置信息Laravel的配置信息保存在config中,你也可以自定义自己的配置信息,只需要使用config('filename.array_key')(支持多级)即可轻松获取配置信息。Laravel的配置信息大多是通过匹配各个服务的门面方式来定义的,比如缓存,你只需要修改config中的默认驱动,就可以很方便的在文件或者redis或者数据库等之间切换。存储介质很多,你可以还可以自定义存储介质。关于门面模式,大家可以自行查看文档和源码,这里就不做介绍了。这里还有一个问题,比如数据库配置。一般我们会区分开发、测试、生产环境,但是config中的配置只能保存在仓库中。这里我们需要用到另外一个特殊的配置文件.envAll如果在配置文件中定义了类似env('DB_HOST','127.0.0.1')的方式就会读取.env文件。第一个参数用作配置名称。如果.env文件中没有定义,将使用第一个参数。返回两个参数的默认值。一般我们会在这个文件中定义所有区分环境的配置。注意这个文件不能提交到仓库,所以拉取代码后可能看不到这个文件。您只需要复制.env.example复制为.env(第一次安装Laravel会自动执行复制)然后配置正确的数据库连接信息数据库迁移(生产环境慎用)。大多数框架都有数据库迁移功能,这对于维护数据库结构的一致性起着非常重要的作用,但是如果这个功能使用不当,风险是非常高的。我的一个同事以前用过这个功能,不小心重置了所有的表。好在数据是有备份的,及时恢复了。Laravel的数据迁移文件在database/migrations中。由于Laravel框架是国外开发者开发的,他们的用户信息主要是email。我们需要在用户表中增加一个手机号码字段。添加提交后,将此字段添加到模型提交中。这里我们直接修改表迁移文件,因为我们没有进行数据库迁移。当你进行数据库迁移后,Laravel会在数据库中记录你迁移的内容,此时如果你想再次修改,应该使用更新表的操作,然后就可以进行数据库迁移操作(开发环境)phpartisanmigrate验证规则Laravel提供了很多验证规则,可以满足大数据场景的验证,一些特殊的验证需要我们自定义验证规则,比如手机号码。我们使用如下命令创建手机号校验规则commitphpartisanmake:rulePhoneNumber添加规则后,我们可以在ServiceProvider中为该规则配置别名提交参数校验,一般可以在controller中直接写规则,或者可以通过定义Requests来单独管理。这里我们采用第二种方式,统一定义Requests中的管理校验逻辑。我们先创建一个Requestcommitphpartisanmake:requestGetSmsCodeRequestRequest来获取验证码。一般我们需要在messages方法中重新定义错误信息。添加Request后,我们就可以直接在controller中使用了。结合我们之前的配置,当验证失败时,会返回如下信息{"code":10004,"msg":"数据验证失败","data":{"phone_number":["请输入您的手机phonenumber"]}}获取验证码到这里我们的基本配置就完成了,下面我们来实际添加一个接口,首先在routes/api.php中添加一个获取验证码的路由(限制访问频率为30分钟100次)commitRoute::middleware('throttle:100,30')->post('getSmsCode',[AuthController::class,'getSmsCode']);然后在ServiceProvider中添加ControllerContractService并绑定Contract和Service的关系commitphpartisanmake:controllerAuthController第一种实现方式参考Laravel的自动注入和Laravel的绑定接口实现这里为了测试方便,附上验证码直接在界面返回,实际使用需要修改为发送短信注册。根据上面的教程,我们首先要添加一个注册路由commitRoute::middleware('throttle:100,30')->post('register',[AuthController::class,'register']);然后添加验证码规则并添加别名commit使用验证码规则创建注册请求commit最后在ControllerContractService中添加方法commit