后端Web框架【免费下载链接】yii2Yii 2: The Fast, Secure and Professional PHP Framework项目地址https://gitcode.com/gh_mirrors/yi/yii2点击查看免费下载RESTful API 请求处理中响应格式化决定客户端最终收到的数据形态资源对象如何变成数组、数组又如何变成 JSON 或 XML 字符串。本篇以 Yii2 框架的docs/guide/rest-response-formatting.md为骨架结合 framework/rest 下的Controller、Serializer与 framework/web 的Response、JsonResponseFormatter源码完整讲解内容协商Content Negotiation、数据序列化Data Serializing以及 JSON 输出控制三个环节读者可据此掌握响应格式的协商机制、分页信封配置与 JSON 编码调优并能在自己的 API 控制器中落地实践。REST 响应格式化的三个阶段当 Yii2 应用处理一个 RESTful API 请求时与响应格式化相关的步骤通常如下确定影响响应格式的各种因素如媒体类型media type、语言、版本等这一过程即内容协商Content Negotiation将资源对象转换为数组该步骤由 yii\rest\Serializer 完成具体转换规则在 Resources资源 一节中说明将数组按内容协商确定的格式转换为字符串由注册在response应用组件 的 yii\web\Response::formatters 属性中的 yii\web\ResponseFormatterInterface 响应格式化器完成。从源码看yii\rest\Controller的afterAction()会调用serializeData()返回结果而serializeData()使用Yii::createObject($this-serializer)-serialize($data)创建并调用序列化器见 framework/rest/Controller.php随后Response::prepare()根据formatters中对应格式的格式化器将数组数据渲染成响应内容见 framework/web/Response.php。三个阶段由此在控制器与响应对象之间串联成完整的格式化流水线。Content Negotiation 内容协商Yii2 通过 yii\filters\ContentNegotiator 过滤器支持内容协商。RESTful API 基础控制器类 yii\rest\Controller 内置了名为contentNegotiator的过滤器提供响应格式协商与语言协商两种能力。协商过程与典型效果该过滤器在 RESTful API 控制器动作执行前检查请求的Accept请求头并将 yii\web\Response::format 设置为对应格式。例如若请求包含如下请求头Accept: application/json; q1.0, */*; q0.1将得到 JSON 格式的响应$ curl -i -H Accept: application/json; q1.0, */*; q0.1 http://localhost/users HTTP/1.1 200 OK Date: Sun, 02 Mar 2014 05:31:43 GMT Server: Apache/2.2.26 (Unix) DAV/2 PHP/5.4.20 mod_ssl/2.2.26 OpenSSL/0.9.8y X-Powered-By: PHP/5.4.20 X-Pagination-Total-Count: 1000 X-Pagination-Page-Count: 50 X-Pagination-Current-Page: 1 X-Pagination-Per-Page: 20 Link: http://localhost/users?page1; relself, http://localhost/users?page2; relnext, http://localhost/users?page50; rellast Transfer-Encoding: chunked Content-Type: application/json; charsetUTF-8 [ { id: 1, ... }, { id: 2, ... }, ... ]整个流程如下动作执行前ContentNegotiator过滤器检查Accept请求头并把响应格式设置为json动作执行后返回资源对象或集合yii\rest\Serializer将结果转换为数组最后由 yii\web\JsonResponseFormatter 把数组序列化为 JSON 字符串并写入响应体。协商的底层实现要点从 framework/filters/ContentNegotiator.php 的源码可以看到协商的完整逻辑negotiate()会先处理formats若支持多于一种格式自动向响应添加Vary: Accept响应头以利于 HTTP 缓存按Accept头区分缓存若存在formatParam默认_formatGET 参数则优先按该参数直接指定格式参数值合法则直接设置Response::format否则抛出 yii\web\NotAcceptableHttpException状态码 406参数为数组时抛出 yii\web\BadRequestHttpException400无_format参数时遍历$request-getAcceptableContentTypes()按 q 值优先级在formats中匹配 MIME 类型匹配成功则同时设置Response::format、acceptMimeType与acceptParams若所有可接受类型都不匹配会回退到formats中的第一个格式仅当请求中没有*/*通配时才抛出 406 异常。语言协商的逻辑类似languageParam默认_langlanguages支持带键映射与无键前缀回退例如en可匹配en-US、en-GB协商结果写入Yii::$app-language。扩展新格式默认情况下 RESTful API 同时支持 JSON 与 XML 两种格式application/json→json、application/xml→xml见 framework/rest/Controller.php。若需支持新格式可在 API 控制器类中配置contentNegotiator过滤器的 formats 属性use yii\web\Response; public function behaviors() { $behaviors parent::behaviors(); $behaviors[contentNegotiator][formats][text/html] Response::FORMAT_HTML; return $behaviors; }formats属性的键是支持的 MIME 类型值是相应的响应格式名称且该名称必须存在于 yii\web\Response::formatters 中。Response 默认注册的格式包括htmlHtmlResponseFormatter、xmlXmlResponseFormatter、jsonJsonResponseFormatter与jsonpJsonResponseFormatter且useJsonp为true。另外ContentNegotiator既可作动作过滤器使用也可作为应用级的bootstrap组件使用它实现了BootstrapInterface后者可对整个应用生效配置方式参见 framework/filters/ContentNegotiator.php 中的注释示例。Data Serializing 数据序列化yii\rest\Serializer 是负责把资源对象或集合转换为数组的核心组件。它识别实现 yii\base\Arrayable 的对象主要是资源对象以及实现 yii\data\DataProviderInterface 的对象资源集合。serialize() 的分派逻辑从源码 framework/rest/Serializer.php 可以看到serialize()按以下顺序分派若数据是带校验错误的Model$data-hasErrors()为true调用serializeModelErrors()将响应状态码设置为422Data Validation Failed.并输出[{field ..., message ...}, ...]结构的错误数组见 framework/rest/Serializer.php若数据实现Arrayable调用serializeModel()并委托$model-toArray($fields, $expand)若数据实现\JsonSerializable调用jsonSerialize()若数据实现DataProviderInterface调用serializeDataProvider()若数据是数组则递归对每个元素调用serialize()其他类型原样返回。序列化器的fieldsParam默认fields与expandParam默认expand支持客户端通过查询参数控制返回字段getRequestedFields()会把逗号分隔的参数解析为字段列表见 framework/rest/Serializer.php。配置序列化器与 collectionEnvelope可通过设置 yii\rest\Controller::serializer 属性为配置数组来定制序列化器。例如若希望把分页信息直接放进响应体以简化客户端开发可配置 yii\rest\Serializer::collectionEnvelope 属性use yii\rest\ActiveController; class UserController extends ActiveController { public $modelClass app\models\User; public $serializer [ class yii\rest\Serializer, collectionEnvelope items, ]; }之后请求http://localhost/users将得到如下响应HTTP/1.1 200 OK Date: Sun, 02 Mar 2014 05:31:43 GMT Server: Apache/2.2.26 (Unix) DAV/2 PHP/5.4.20 mod_ssl/2.2.26 OpenSSL/0.9.8y X-Powered-By: PHP/5.4.20 X-Pagination-Total-Count: 1000 X-Pagination-Page-Count: 50 X-Pagination-Current-Page: 1 X-Pagination-Per-Page: 20 Link: http://localhost/users?page1; relself, http://localhost/users?page2; relnext, http://localhost/users?page50; rellast Transfer-Encoding: chunked Content-Type: application/json; charsetUTF-8 { items: [ { id: 1, ... }, { id: 2, ... }, ... ], _links: { self: { href: http://localhost/users?page1 }, next: { href: http://localhost/users?page2 }, last: { href: http://localhost/users?page50 } }, _meta: { totalCount: 1000, pageCount: 50, currentPage: 1, perPage: 20 } }可见启用信封后响应体结构变为{ items: [...], _links: {...}, _meta: {...} }其中_links由Pagination::getLinks(true)生成_meta由分页对象的总数、页数、当前页与每页条数组成见 framework/rest/Serializer.php。同时原有分页 HTTP 头X-Pagination-*与Link仍然保留——serializeDataProvider()在返回数据前会调用addPaginationHeaders()写入这些头见 framework/rest/Serializer.php默认头名称由totalCountHeader、pageCountHeader、currentPageHeader、perPageHeader四个属性控制。Serializer 还提供其他实用属性linksEnvelope默认_links与metaEnvelope默认_meta仅在collectionEnvelope设置时生效可自定义信封键名自 2.0.4 起preserveKeys默认false自 2.0.10 起设为true时保留集合数组的键可将集合序列化为以键索引的 JSON 对象而非数组对于HEAD请求serializeModel()与serializeDataProvider()直接返回null从而不产生响应体见 framework/rest/Serializer.php 与第 262-270 行。对应行为在 tests/framework/rest/SerializerTest.php 中有完整的单元测试覆盖可作为理解各种属性组合效果的可执行参考。Controlling JSON Output 控制 JSON 输出JSON 响应由 yii\web\JsonResponseFormatter 生成内部使用 yii\helpers\JsonJSON 助手。该格式化器可在response应用组件的 formatters 属性中配置应用配置参见 concept-configurationsresponse [ // ... formatters [ \yii\web\Response::FORMAT_JSON [ class yii\web\JsonResponseFormatter, prettyPrint YII_DEBUG, // use pretty output in debug mode encodeOptions JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE, // ... ], ], ],常用格式化选项prettyPrint默认false设为true时会在编码选项上追加JSON_PRETTY_PRINT输出易读的格式化 JSON适合开发调试环境如示例中的YII_DEBUGencodeOptions默认值320即JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE见 framework/web/JsonResponseFormatter.php可按 PHP 的json_encode()选项位掩码自由组合例如增加JSON_NUMERIC_CHECK强制数字字符串转为数字contentType自 2.0.14 起支持自定义Content-Type响应头默认按useJsonp取值分别为application/json; charsetUTF-8或application/javascript; charsetUTF-8useJsonp开启 JSONP 模式时要求响应数据是包含data与callback两个成员的数组输出形如callback(data);若数据不满足要求会记录 warning见 framework/web/JsonResponseFormatter.phpkeepObjectType自 2.0.44 起设为true可避免零起始索引的数组被编码为 JSON 数组而是按对象输出与json_encode()行为一致。从 framework/web/JsonResponseFormatter.php 的实现可以看出格式化时若prettyPrint为真则在encodeOptions上按位或JSON_PRETTY_PRINT随后调用Json::encode($response-data, $options)写入$response-contentkeepObjectType在编码前后临时调整Json::$keepObjectType并恢复以避免影响后续请求。关于数值类型的一个关键提醒使用 DAO 数据库层返回的数据一律以字符串形式表示这在 JSON 中并不总是期望的结果——尤其是数值字段本应以数字类型呈现。而使用 ActiveRecord 层获取数据库数据时数值列的值会在 yii\db\ActiveRecord::populateRecord() 中按表结构的列类型进行 PHP 类型转换phpTypecast因此返回的数值字段会成为整数/浮点数从而在 JSON 中正确输出为数字而非字符串。这是选择 DAO 还是 ActiveRecord 输出 API 数据时需要注意的差异点。小结Yii2 的 REST 响应格式化由「内容协商 → 数据序列化 → 格式化器输出」三段流水线构成ContentNegotiator依据Accept头与_format参数确定Response::formatSerializer将资源对象/数据提供器转换为数组并注入分页信息头或信封JsonResponseFormatter/XmlResponseFormatter等格式化器最终把数组渲染为响应体字符串。开发者可通过contentNegotiator的formats扩展媒体类型通过控制器serializer属性定制collectionEnvelope等信封与键保留行为并在response组件中精细控制prettyPrint、encodeOptions等 JSON 编码细节从而构建出格式协商灵活、数据结构可控、编码风格统一的高质量 RESTful API。赞分享后端Web框架【免费下载链接】yii2Yii 2: The Fast, Secure and Professional PHP Framework项目地址https://gitcode.com/gh_mirrors/yi/yii2点击查看免费下载相关推荐Yii2 RESTful API 响应格式化指南内容协商、Serializer 序列化与 JSON/XML 输出控制Yii2 RESTful API 响应格式化指南内容协商、Serializer 序列化与 JSON/XML 输出控制 导读 在 Yii2 中一次 RESTf后端Web框架chatgpt-java响应格式定制ResponseFormat与JSON输出控制chatgpt java响应格式定制ResponseFormat与JSON输出控制 在集成ChatGPT API时你是否遇到过AI返回格式混乱导致解析失败的Autoformer未来展望从Nature Machine Intelligence到下一代时间序列AIAutoformer未来展望从Nature Machine Intelligence到下一代时间序列AI Autoformer作为NeurIPS 2021的创人工智能深度学习机器学习上一篇如何用NLTK分词word_tokenize、Punkt、正则8种分词器实战对比与选型教程下一篇如何把一张发灰的 RAW 救回出片darktable 暗房 6 个关键模块实战指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考