Sails Create 蓝图动作完全指南:POST /:model 创建记录、校验响应与 Socket 实时通知 📅 发布时间:2026/9/20 19:41:58 👁 浏览次数: Sails Create 蓝图动作完全指南POST /:model 创建记录、校验响应与 Socket 实时通知【免费下载链接】sailsRealtime MVC Framework for Node.js项目地址: https://gitcode.com/gh_mirrors/sa/sails本篇技术指南围绕 SailsRealtime MVC Framework for Node.js内置的Create 蓝图动作Blueprint Action展开讲解如何通过POST /:model这一隐式 REST 路由向数据库创建新记录包括请求参数的组织方式、成功/失败响应结构、以及与 WebSockets 结合时自动广播的 created 实时通知。读完本文你将掌握 Create 蓝图的完整调用契约并能从源码层面理解其执行链路进而在实际项目中正确使用、覆盖或定制这一动作。Create 蓝图是什么Create 蓝图是 Sails 为每个模型自动生成的 CRUD 接口之一用于在数据库中创建一条新记录。它的入口非常简单POST /:model其中:model是模型的 identity小写化的模型名。当请求命中该端点后Sails 会读取请求体request body中的参数作为新记录的属性值写入数据库并返回一个 JSON 字典表示新创建的实例。若发生校验validation错误则返回包含无效属性信息的 JSON 响应并伴随400状态码。对应的实现位于 lib/hooks/blueprints/actions/create.js它被注册为每个模型的create动作见 lib/hooks/blueprints/index.js 中registerActions对BlueprintController.create的注册逻辑。路由是如何生成的Create 蓝图动作可以通过两类隐式路由被触发二者默认均处于开启状态可在 sails.config.blueprints 中调整路由类型生成规则默认开关说明REST 路由post /:model如POST /ponyrest: true生产环境推荐语义化 HTTP 动词快捷路由shortcutget /:model/create如GET /pony/createshortcuts: true仅建议开发期使用生产环境应关闭在 lib/hooks/blueprints/index.js 的bindShadowRoutes中可以看到两条绑定语句REST 风格_bindRestRoute(post %s, create)绑定到identity /create动作快捷风格_bindShortcutRoute(get %s/create, create)。两条路由都会携带{ model: identity, associations: ..., autoWatch: ... }等路由选项供后续的parseBlueprintOptions解析使用。此外通过prefix如/api/v2和restPrefix可以给这些隐式路由统一加前缀pluralize: true则会把路由中的模型名复数化如POST /ponies。这些配置项的默认值与类型都定义在 lib/hooks/blueprints/index.js 的defaults.blueprints中。请求参数详解Create 蓝图的参数应通过**请求体request body**发送。Sails 默认能理解最常见的几种 body 编码url-encoded、form-encoded以及JSON。此外当使用快捷路由GET /:model/create时参数也可以放在查询字符串中。参数类型说明modelstring要创建记录的模型 identity例如POST /purchase中的purchase*json?与模型上定义的属性同名的 body 参数用于为新记录设置对应属性值。其处理方式与直接调用模型的.create()方法传入的值完全一致从源码看parse-blueprint-options.js 中case create分支通过req.allParams()收集所有请求参数作为newRecord并且会额外尝试将集合collection关联属性的字符串形式解析为 JSON 数组以便在快捷路由GET 请求中也能设置关联// lib/hooks/blueprints/parse-blueprint-options.js _.each(Model.attributes, function(attrDef, attrName) { if (attrDef.collection (!req.body || !req.body[attrName]) (req.query _.isString(req.query[attrName]))) { try { values[attrName] JSON.parse(req.query[attrName]); } catch(unusedErr) {} } });同时该分支还会设置queryOptions.meta { fetch: true }要求 Waterline 在创建后返回新记录供后续响应与广播使用。实战示例创建一条带关联的记录假设api/models/Pony.js定义了Pony模型包含name、hobby属性以及指向Purchase的多对多关联involvedInPurchases。现在创建一个名为 Applejack、爱好 pickin、并关联购买记录 #13 与 #25 的小马POST /pony{ name: Applejack, hobby: pickin, involvedInPurchases: [13, 25] }示例响应创建成功后Sails 返回新记录的 JSON 字典其中关联属性被填充为完整的子记录对象{ id: 47, name: Applejack, hobby: pickin, createdAt: 1485550575626, updatedAt: 1485550603847, involvedInPurchases: [ { id: 13, amount: 10000, createdAt: 1485550525451, updatedAt: 1485550544901 }, { id: 25, amount: 4.50, createdAt: 1485550561340, updatedAt: 1485550561340 } ] }响应中id、createdAt、updatedAt等由框架/数据库自动生成的字段也会一并返回关联数据默认会被填充默认的填充数量上限为 30见 parse-blueprint-options.js 中的DEFAULT_POPULATE_LIMIT。成功与失败响应成功200 OK创建成功后返回200 OK及新记录 JSON。源码中create.js 在Model.create(data).meta(queryOptions.meta)执行完成后会再次以findOne按主键回查并按populates填充关联最后通过res.ok(populatedRecord)返回// lib/hooks/blueprints/actions/create.js Model .findOne(newInstance[Model.primaryKey], queryOptions.populates) .exec(function foundAgain(err, populatedRecord) { if (err) { return res.serverError(err); } if (!populatedRecord) { return res.serverError(Could not find record after creating!); } ... res.ok(populatedRecord); });失败400 Bad Request校验错误如果请求参数无法通过模型定义中的校验类型错误、缺少必填属性等或触发了唯一性约束Sails 会返回400状态码及错误信息。源码中的错误分类逻辑如下create.jsswitch (err.name) { case AdapterError: switch (err.code) { case E_UNIQUE: return res.badRequest(err); // 唯一性约束冲突 default: return res.serverError(err); } case UsageError: return res.badRequest(formatUsageError(err, req)); // 参数用法错误 default: return res.serverError(err); // 其余为 500 服务端错误 }对于 Waterline 抛出的UsageError例如参数类型不匹配formatUsageError.js 会为其附加一个toJSON()方法返回便于程序解析的{ code, details, message }结构message在非生产环境还会额外附上排查提示如 check that your client-side code sends data for every required attribute在生产环境则保持精简。这解释了为什么同一类错误在不同环境下返回的消息详略不同。Socket 实时通知resourceful PubSub如果应用启用了 WebSocketsCreate 蓝图会自动与 resourceful PubSub 机制联动向关注的客户端广播实时消息。自动订阅autoWatch当autoWatch开启时默认开启所有正在监听该模型的客户端 socket即此前调用过 Find 蓝图动作的 socket都会收到一条created通知。这些监听 socket 同时也会被自动订阅到新记录上以便接收该记录后续的变更消息。背后的机制见 lib/hooks/blueprints/actions/find.jssocket 请求 Find 时若req.options.autoWatch为真会执行Model._watch(req)将 socket 加入模型的类房间class room而autoWatch这个路由选项正是在bindShadowRoutes绑定隐式路由时从sails.config.blueprints.autoWatch注入的。created 通知的消息格式当新记录创建时Sails 会向模型类房间广播事件名为模型 identity如user的通知消息体结构为verb: created, data: 新记录的属性值字典不含关联 id: 新记录的主键沿用上面的例子所有监听User模型的客户端发起请求的那个 socket 除外将收到{ id: 47, verb: created, data: { id: 47, name: Applejack, hobby: pickin, createdAt: 1485550575626, updatedAt: 1485550603847 } }请求方 socket 的额外订阅如果 Create 蓝图是通过socket 请求触发的那么发起请求的 socket 还会被额外订阅到新建记录源码中对应Model.subscribe(req, [populatedRecord[Model.primaryKey]])。这意味着之后若该记录通过蓝图被更新或删除这个 socket 也会收到通知。更多细节见.subscribe()。关联子记录的通知addedTo / removedFrom示例中involvedInPurchases是一个带via的集合关联。由于新记录在创建时就设置了关联值对于关联关系中另一侧的模型本例是Purchase凡是已订阅购买记录 #13、#25 的客户端会收到addedTo通知而如果某条子记录此前已经属于别的父记录多对一场景例如User.create({pets: [1,2,3]})中pets集合的via指向Pet.owner那么旧父记录上会触发removedFrom通知——create.js在创建前会先用async.reduce遍历所有多对一集合属性找出已有父记录的子项并预收集removedFromNotificationsToSend列表创建成功后统一通过Model._publishRemove(...)发送。底层广播实现上述广播最终由 pubsub 钩子完成见 lib/hooks/pubsub/index.js_watch(req)把 socket 加入sails_model_create_identity类房间_publishCreateSingle(values, req)构造{ verb: created, data: values, id: pk }载荷并广播到类房间同时调用_introduce(id)把类房间的所有成员介绍到新记录的实例房间sails_model_identity_id:identity_introduce(model)通过sails.sockets.addRoomMembersToRooms将类房间成员批量加入新实例房间。因此一旦某 socket 因为autoWatch加入了类房间它不仅能收到created通知还会被自动带入新记录的实例房间从而持续收到该记录后续的updated、destroyed等消息。配置与定制关键配置项配置项类型默认值作用autoWatchbooleantrue是否让 Find/FindOne 蓝图中请求的 socket 订阅新记录创建通知restbooleantrue是否生成POST /:model等 REST 蓝图路由shortcutsbooleantrue是否生成GET /:model/create等快捷路由开发便利生产建议关闭prefixstring所有蓝图路由的挂载前缀如/api/v2restPrefixstring仅 REST 蓝图路由的前缀与prefix拼接pluralizebooleanfalse蓝图路由中的模型名是否复数化parseBlueprintOptionsfunction默认实现完全定制蓝图动作行为如默认 limit、populate 策略完整说明参见 sails.config.blueprints。覆盖 Create 蓝图若想针对某个模型替换默认的 Create 行为官方推荐在对应的控制器或独立动作文件中编写同名动作create它会自动覆盖蓝图动作若想全局定制可在config/blueprints.js中提供自定义的parseBlueprintOptions。典型做法是先调用默认实现、再修改返回的查询选项// config/blueprints.js module.exports { blueprints: { parseBlueprintOptions: function(req) { // 获取默认查询选项 var queryOptions req._sails.hooks.blueprints.parseBlueprintOptions(req); // 例如对 create 之外的查询强制 limit 上限 if (req.options.blueprintAction find) { if (queryOptions.criteria.limit 100) { queryOptions.criteria.limit 100; } } return queryOptions; } } };注意parseBlueprintOptions返回的键如newRecord、meta、populates、using即 blueprint action 直接使用的查询选项修改它即可影响 Create 动作最终写入数据库的数据与查询元信息。源码执行链路小结结合上述分析一次POST /:model请求在 Sails 内部的完整链路为请求命中隐式 REST 路由post /:model或快捷路由get /:model/create被绑定到identity /create动作lib/hooks/blueprints/index.jscreateRecord动作调用parseBlueprintOptions(req)生成查询选项using模型 identity、newRecord全部请求参数、meta: { fetch: true }、默认populatesparse-blueprint-options.js预扫描多对一集合关联收集需要广播removedFrom的子记录列表执行Model.create(data).meta(queryOptions.meta)区分AdapterError/E_UNIQUE、UsageError与其他错误分别返回400或500创建成功后以findOne回查并填充关联返回res.ok(populatedRecord)若 pubsub 钩子存在请求方 socket 若为 socket 请求则订阅新记录向类房间广播created通知并_introduce新实例对关联变更发送addedTo/removedFrom通知lib/hooks/pubsub/index.js。理解这条链路后无论你是直接消费该 JSON API、还是基于 WebSockets 构建实时应用、抑或要覆盖默认行为都能准确预判 Create 蓝图的行为边界。【免费下载链接】sailsRealtime MVC Framework for Node.js项目地址: https://gitcode.com/gh_mirrors/sa/sails创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考