Laravel 开发 RESTful API 的一些心得
最近用 Laravel 写了一段时间的 API,总结一下自己的心得吧。
Start
- API开发我们可以看到,有些网站用token验证身份,有些用OAuth2.0,当时我也纠结,然后看到一个不错的说法。大方面,会涉及到给别人用的使用OAuth,自己使用的用token就足够了
- 设计最初,最好在路由加个版本号,方便以后扩展
Route::prefix('v1')->group(function () { // more });
- 如果前端想跨域,请使用这个很方便的包barryvdh/laravel-cors
一个简单的接口示例
验证
- API 开发总会离不开验证,这里推荐使用jwt-auth,1.0 快要来了,新版本的文档也很清晰
- 刚用
jwt-auth
时有疑问,Laravel自带的token验证使用的是数据库api_token字段验证,而不见jwt-auth
需要这个- 然后想自己看源码,结果
QAQ
- 最后去问了官方 >_<
- 原来用户的信息已经存储在token中加密
- 一开始有疑问,这样保存,不会被解密吗(真为自己智商担忧 !_!)
- 后来才想起,jwt一开始就运行
php artisan jwt:secret
生成了秘钥 - 你不泄露就保证安全了~~~
路由
- 然后想自己看源码,结果
- 当然使用官方
api
的路由Route::apiResource()
,一条更比五条强 - 路由的名字当然是RESTful的方式
- 保持动词,复数形式,见名知义
- 有些长的路由,应该用什么分隔呢?
- laravel用的是中划线(-),因为谷歌收录时,按中划线划分关键字,国内的是按下划线(_)收录,具体看自己了,我是喜欢下划线 >_<
- 更多看这里: 路由命名规范
表单验证
可以使用控制器自带的表单验证,更推荐使用 表单类,能分离都分离出去,控制器不要处理太多事情。
能分离的代码都不要吝啬~~~数据转换
- Laravel自带的API Resource
- 用起来真的很方便,不过发现一个问题,
--collection
的格式总是转不过来,后来直接放弃了 - 单个的使用
Resources
- 集合的使用
Resources::collection()
发现,特别好用 >_< - 不得不说,多对多关联时,
Laravel
处理得太好了条件关联 - 在上面这个例子中,如果关联没有被加载,则 posts 键将会在资源响应被发送给客户端之前被删除。
- 在有不确定是否输出关联数据时,这是一个很有用的功能!!!
响应输出
当时在 laravel-china 看到的这个帖子,然后觉得这个方式不错,所以自己也这样子,使用基类的方法统一响应输出。
异常
异常算是一大手笔了,处理好异常,可以让你的代码优雅很多。
\App\Exceptions\Handler::render
方法可以捕获到很多有用的异常,例如,我的代码是这样写的:UnauthorizedHttpException
这个是捕获jwt
异常ValidationException
这个是表单异常,捕获之后,表单错误消息可以很好的格式化,ModelNotFoundException
这个是模型找不到的异常,捕获之后,可以直接在控制器直接这样
// 未捕获之前的写法
public function show($id)
{
$user = User::find($id);
if (! $user) {
}
// do something
}
// 现在
public function show($id)
{
$user = User::findOrFail($id);
}
// 甚至这样
public function show(User $user)
{
// do something
}
- 下面这两个异常可以不捕获,只是方便开发中查看错误消息
NotFoundHttpException
404路由找不到的异常,没什么好说的了MethodNotAllowedHttpException
这个是方法不对应,比如你是get路由,却post请求文档
- 差点忘了这个,文档非常非常重要
- 我是不怎么喜欢在注释写文档的
- 使用
swagger-ui
+swagger-edit
- 下载swagger-ui
- 只需要
dist
目录的东西(其他可以删除了) - 下载swagger-editor
- 只要
dist
目录的东西和根目录的index.html
- 我还把
swagger-editor
的index.html
改成了edit.html
,然后把这两个东西整合到同一个目录(记得修改css,js的位置) - 新建两个文件
api.json
,api.yaml
大概就和图中差不多 - 要修改图中箭头所示成为
api.json
的位置
- 访问
edit.html
可以书写文档 - 访问
index.html
可以查看文档 - 在
edit.html
写好之后,导出json
,然后粘贴到api.json
文件 - 记得也把写好的格式保存到
api.yaml
,因为清楚缓存之后,下次访问时会消失自己写了一个packages
- 就方便创建控制器,验证
- 所有控制器继承重写过的基类,响应输出方便。
- 例如完整验证只需要三秒钟
- 第一秒:
php artisan api:auth
- 第二秒: 出现图代表成功;
- 第三秒: 拿出手臂的劳力士,确定只过了三秒
- 第一秒:
- 更多的使用:laravel-api-helper
工作和API开发有关,用到其他有经验了再回来补补。
更多参考
本作品采用《CC 协议》,转载必须注明作者和本文链接
本帖由 Summer
于 6年前 加精
我建议统一响应类的设计,最好用实现 responsable 接口,好一点。
jwt的token本身是明文的, key只用来签名
jws才是加密.
@Aaron 因为有一个状态类继承了 response 对象,响应用 laravel 的方便
@symoo jwt 应该并不是明文 的,因为有一个
JWT_SECRET
来使信息加密了。jwt-auth 有时间的朋友去研究一下吧,刚才看了源码,有点心酸,转来转去,最后用了个 sha256 签名,然后又用了 hash 加密,头晕,有看得透彻的朋友可以说一下 >_
@DavidNineRoc jwtauth说白了就是把user id用后端定义的jwt-secret加密了,响应的token里有base64加密的其他配置比如加密方法,说的再透彻一点就是把用户id存到了header的Authorization中,服务端也会缓存这个token
@山海王子 学习了:+1:
跨域,用 包barryvdh/laravel-cors
不就是一句Access-Control-Allow-Origin: *
就可以了 为啥还要搞的那么麻烦@datou 这样写是行呀,然后你想全局使用,得新建一个中间件,然后你又想配置只允许某些域名跨域,又得加一个配置文件。
这些时间足够你运行
composer update
了:smile:jwt并不会加密user_id,user_id 和 其他payload都是明文base64的。不过后面会有一个通过JWT_SECRET 和用户信息 payload生成的串来验证 你的 user_id 和其他payload 被没被串改
jwt 中间会用'.'来连接,你可以看下中间那段直接base64解密一下你的用户ID就出来了,但是你想随便改个用户ID放回去,你就会发现验证不通过了
@hooklife 受教了,也看到了 jwt-auth 的有一个 issure 也说了这个事情
阔以。
个人觉得还是用自定义的状态码好点,毕竟http提供的状态码并不能根据业务去提示。
@Hatcher 这个状态码当然是自定义的,暴露的 setCode 方法就是为了设置状态码的
@DavidNineRoc 嗯嗯
唉,现在jwt支持多用户表吗?
@仰望 支持的,切换不同守卫即可。
@symoo jws没有接触过.得去查找下
很好,收获。
有一个非常严重的问题,需要问一下作者:文章中
表单验证
这一块里面的message()
方法是提示错误语义信息的,所有如果在用postman
的时候用这种方法的话,就会被back()
回去,弹不出错误信息,应该怎么让后台api
调试变得也方便呢?@张浩浩浩浩 这个异常捕获不会因为是不是 postman 而特殊,都会返回 json 响应。你的描述我也听得不是很明白。
@DavidNineRoc 那我就简化一下我的问题:
Request
里的extends
继承类是:FormRequest
,这里面的源码有一个方法:这里面 很明显 有一个重定向
->redirectTo($this->getRedirectUrl())
,如果表单验证走了error
之后,它会back()
回去,但是如果Api
接口, 我们都用postman
没法打印出具体是什么错误,只会显示:https://cdn.learnku.com/uploads/image...
@张浩浩浩浩
捕获异常这一步做了吗,如果写了异常,表单发生错误可以在这里返回 json
@DavidNineRoc 谢谢博主的耐心解答,解决了我的大问题。
创建绑定了一个契约接口
然后实现接口
json
返回数据:另一个代码生成器的包