|
ThinkPHP从创建到发布API,从创踩过的发布坑比代码还多。去年我接手一个二手书交易平台,从创后端用TP6,发布从零搭到上线,从创前后折腾了三个星期。发布核心就一句话:别把框架当黑盒,从创得把它当工具箱,发布每个螺丝都得亲手拧过才算数。从创 创建项目那步就有人栽跟头。发布composer create-project topthink/think tp_api 这行命令敲下去,从创看似简单,发布但PHP版本必须≥7.2.5,从创否则直接报错。发布我同事用7.1跑,从创卡在依赖安装上,换了版本才通。装完第一步不是写代码,是改.env文件,数据库连接、调试开关、日志路径全在这里。调试模式一定开着,不然报错信息像被嚼过的口香糖,粘成一团看不清。 路由设计是命门。TP6默认是pathinfo模式,访问 /api/v1/book/1 这种URL,得先配路由规则。我在route/app.php里写: Route::get('api/v1/book/:id', 'api.Book/read'); 这行代码决定了整个接口的入口。别用控制器自动映射,那会让URL暴露内部结构,安全性差一截。参数绑定用:id这种占位符,比$_GET['id']干净得多,而且能自动过滤非法字符。 控制器写业务逻辑时,我犯过最蠢的错误——把所有查询堆在控制器里。后来拆成三层:控制器只接收参数和返回结果,逻辑层处理业务判断,模型层管数据库操作。比如获取图书列表,控制器调Logic层的getBooks(),Logic层再调Model的where条件查询。这样改一个需求不用翻整座代码山,只动对应层就行。 模型里有个坑,TP6的软删除是全局的。我在Book模型里用了SoftDelete trait,结果所有查询自动带上delete_time IS NULL条件。测试时发现列表少了数据,排查半天才找到原因。要是想查含已删除的数据,得用withTrashed()方法显式指定。这个细节官方文档写得含糊,实战中碰一次就记住了。 验证器不能省。前端传来的参数,我见过有人直接塞进where条件,SQL注入就是这么来的。TP6的验证器用起来顺手,定义一个BookValidate类,规则写在$rule属性里: protected $rule = [ 'title' => 'require|max:100', 'price' => 'number|between:0,999' ]; 控制器里用validate()门面调用,失败会抛出异常,配合全局异常处理返回JSON错误信息。这步做扎实,接口的健壮性直接上一个台阶。 发布前的最后一步,是处理跨域和响应格式。前端用Vue,请求走axios,不配跨域头浏览器直接拦截。我在中间件里加了Access-Control-Allow-Origin: *,但生产环境得换成具体域名。响应格式我统一封装成: { "code": 0, "message": "success", "data": { ...} } 用tp6的json()函数返回,前端拿到后统一处理code,不用每个接口单独判断状态码。 上线那天,我用postman压测了50个并发请求,服务器CPU飙到80%。查日志发现是数据库查询没加索引,给book表的category_id字段加了索引后,降到15%。这个教训告诉我,框架调优再漂亮,数据库设计跟不上照样白搭。 最后说个玄学问题。TP6在PHP8.0下偶尔报undefined array key的警告,原因是框架内部有些写法没跟上新版本。解决办法是把error_reporting级别调低,或者升级到TP6.1。别问为什么,社区issue里都是这么解决的,你要是纠结源码,三天三夜看不完。 从创建到发布,流程就这么走完。框架是工具,思路才是核心。把业务拆清楚,每一层各司其职,API自然稳如老狗。 |