<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>服务端 on 土土哥的技术 Blog</title><link>https://tutuge.me/categories/%E6%9C%8D%E5%8A%A1%E7%AB%AF/</link><description>Recent content in 服务端 on 土土哥的技术 Blog</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><copyright>tutuge</copyright><lastBuildDate>Mon, 02 May 2016 00:00:00 +0000</lastBuildDate><atom:link href="https://tutuge.me/categories/%E6%9C%8D%E5%8A%A1%E7%AB%AF/index.xml" rel="self" type="application/rss+xml"/><item><title>API返回结果设计经验与总结</title><link>https://tutuge.me/2016/05/02/design-json-api-respoense/</link><pubDate>Mon, 02 May 2016 02:44:49 +0000</pubDate><guid>https://tutuge.me/2016/05/02/design-json-api-respoense/</guid><description>&lt;h2 id="前言"&gt;&lt;a href="#%e5%89%8d%e8%a8%80" class="header-anchor"&gt;&lt;/a&gt;前言
&lt;/h2&gt;&lt;p&gt;RESTful API的设计已经很成熟了，大家也都比较认可。本文也不再过多介绍RESTful API相关的知识，而是针对JSON型API的返回结果设计，总结下自己的经验。&lt;/p&gt;
&lt;h2 id="结构"&gt;&lt;a href="#%e7%bb%93%e6%9e%84" class="header-anchor"&gt;&lt;/a&gt;结构
&lt;/h2&gt;&lt;p&gt;先来看看返回结果的结构示例：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;{
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; data : { // 请求数据，对象或数组均可
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; user_id: 123,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; user_name: &amp;#34;tutuge&amp;#34;,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; user_avatar_url: &amp;#34;http://tutuge.me/avatar.jpg&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; },
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; msg : &amp;#34;done&amp;#34;, // 请求状态描述，调试用
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; code: 1001, // 业务自定义状态码
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; extra : { // 全局附加数据，字段、内容不定
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; type: 1,
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; desc: &amp;#34;签到成功！&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="data字段---请求数据"&gt;&lt;a href="#data%e5%ad%97%e6%ae%b5---%e8%af%b7%e6%b1%82%e6%95%b0%e6%8d%ae" class="header-anchor"&gt;&lt;/a&gt;data字段 - 请求数据
&lt;/h3&gt;&lt;p&gt;首先是本次请求结果的数据&lt;code&gt;data&lt;/code&gt;字段，其值为对象（字典）或数组均可以，根据业务而定。&lt;/p&gt;
&lt;p&gt;如请求的是某个用户的个人profile信息，就可以是对象，对象里面是用户profile的键值对数据，如&lt;code&gt;user_id: 123&lt;/code&gt;、&lt;code&gt;user_name: &amp;quot;tutuge&amp;quot;&lt;/code&gt;等。&lt;/p&gt;
&lt;p&gt;如果请求的是列表数据，就可以是数组，如请求用户列表：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-groovy" data-lang="groovy"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nl"&gt;data:&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;user_id:&lt;/span&gt; &lt;span class="mi"&gt;123&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;user_name:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;tutuge&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;user_id:&lt;/span&gt; &lt;span class="mi"&gt;321&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;user_name:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;zekunyan&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;},&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;数组、对象，相互嵌套，灵活组合即可。&lt;/p&gt;
&lt;p&gt;对于iOS来说，解析&lt;code&gt;data&lt;/code&gt;字段是对象还是数组也很容易，在接收到JSON数据字典后，如AFNetworking的返回结果，对&lt;code&gt;data&lt;/code&gt;判断其类型即可：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-groovy" data-lang="groovy"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;([&lt;/span&gt;&lt;span class="n"&gt;jsonDict&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;data&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="nl"&gt;isKindOfClass:&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;NSDictionary&lt;/span&gt; &lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="o"&gt;]])&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// JSON对象
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;([&lt;/span&gt;&lt;span class="n"&gt;jsonDict&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;data&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="nl"&gt;isKindOfClass:&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;NSArray&lt;/span&gt; &lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="o"&gt;]])&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// JSON数组
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="msg字段---请求状态描述调试用"&gt;&lt;a href="#msg%e5%ad%97%e6%ae%b5---%e8%af%b7%e6%b1%82%e7%8a%b6%e6%80%81%e6%8f%8f%e8%bf%b0%e8%b0%83%e8%af%95%e7%94%a8" class="header-anchor"&gt;&lt;/a&gt;msg字段 - 请求状态描述，调试用
&lt;/h3&gt;&lt;p&gt;&lt;code&gt;msg&lt;/code&gt;字段是本次请求的业务、状态描述信息，主要用于调试、测试等。&lt;/p&gt;
&lt;p&gt;如“done”、“请求缺少参数！”&lt;/p&gt;
&lt;p&gt;服务端可以自由发挥，开发人员看得懂就好。 -_-|||&lt;/p&gt;
&lt;h3 id="code字段---业务自定义状态码"&gt;&lt;a href="#code%e5%ad%97%e6%ae%b5---%e4%b8%9a%e5%8a%a1%e8%87%aa%e5%ae%9a%e4%b9%89%e7%8a%b6%e6%80%81%e7%a0%81" class="header-anchor"&gt;&lt;/a&gt;code字段 - 业务自定义状态码
&lt;/h3&gt;&lt;p&gt;&lt;code&gt;code&lt;/code&gt;字段，业务自定义的状态码。&lt;/p&gt;
&lt;p&gt;其实是否要在API里面自定义业务状态码，&lt;strong&gt;非常有争议&lt;/strong&gt;=。=，因为Http请求本身已经有了完备的状态码，再定义一套状态码直观上感受却是不对劲。但是实际开发中，确实发现自定义业务状态码的必要性，如一次成功的Http status 200的请求，可能由于用户未登录、登录过期而有不同的返回结果和处理方式，所以还是保留了&lt;code&gt;code&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;状态码的定义也最好有一套规范，如按照用户相关、授权相关、各种业务，做简单的分类：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;// Code 业务自定义状态码定义示例
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;// 授权相关
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;1001: 无权限访问
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;1002: access_token过期
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;1003: unique_token无效
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;...
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;// 用户相关
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2001: 未登录
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2002: 用户信息错误
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;2003: 用户不存在
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;// 业务1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;3001: 业务1XXX
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;3002: 业务1XXX
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;// ...
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;Code&lt;/code&gt;业务状态码最好是用常量定义的，当然有能力的动态配置更新更好，这里就不再详细说明。&lt;/p&gt;
&lt;p&gt;Http的状态码参考：&lt;a class="link" href="https://en.wikipedia.org/wiki/List_of_HTTP_status_codes" target="_blank" rel="noopener"
 &gt;List of HTTP status codes&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="extra字段---全局附加数据"&gt;&lt;a href="#extra%e5%ad%97%e6%ae%b5---%e5%85%a8%e5%b1%80%e9%99%84%e5%8a%a0%e6%95%b0%e6%8d%ae" class="header-anchor"&gt;&lt;/a&gt;extra字段 - 全局附加数据
&lt;/h3&gt;&lt;p&gt;&lt;code&gt;extra&lt;/code&gt;字段，用来表示全局的附加数据。&lt;/p&gt;
&lt;p&gt;这个字段来源于之前做项目时，用户的操作（数据请求），会导致用户的等级、经验变化，而具体什么时候产生不确定，由服务端的规则决定，并且客户端要及时向用户展示变化，所以加上了&lt;code&gt;extra&lt;/code&gt;字段。&lt;/p&gt;
&lt;p&gt;在设计&lt;code&gt;extra&lt;/code&gt;字段的时候，并没有对其结构内容做限制，所以比较灵活，但是还是要有个&lt;code&gt;type&lt;/code&gt;字段，来做约束，如：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-dts" data-lang="dts"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 升级
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nl"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nl"&gt;show_msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;恭喜您升级到XXX&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 完成任务
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nl"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nl"&gt;task_desc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;达成XXX成就&amp;#34;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;总的来说就是自由发挥，只要服务端、客户端相互沟通好即可。当然，也要避免乱用，保证真的需要全局附加数据才使用这个字段。&lt;/p&gt;
&lt;h2 id="最佳实践"&gt;&lt;a href="#%e6%9c%80%e4%bd%b3%e5%ae%9e%e8%b7%b5" class="header-anchor"&gt;&lt;/a&gt;最佳实践
&lt;/h2&gt;&lt;p&gt;总结几点最佳实践。&lt;/p&gt;
&lt;h3 id="规范统一的命名"&gt;&lt;a href="#%e8%a7%84%e8%8c%83%e7%bb%9f%e4%b8%80%e7%9a%84%e5%91%bd%e5%90%8d" class="header-anchor"&gt;&lt;/a&gt;规范统一的命名
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;命名风格统一&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;不管是驼峰式还是下划线式，统一就好。当然，按照目前的“大众规范”，还是统一小写加下划线比较好=。=
如：&lt;code&gt;user_id&lt;/code&gt;，&lt;code&gt;user_name&lt;/code&gt;，&lt;code&gt;user_age&lt;/code&gt;等。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;语义清晰，遵守常用缩写&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;字段的名字最好能体现字段的类型，遵守一些“常用”的缩写，如：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ceylon" data-lang="ceylon"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 字符串
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;user_name&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;task_desc&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;date_str&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;article_title&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;feed_content&lt;/span&gt; &lt;span class="err"&gt;等&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 数字
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;users_count&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;task_num&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;xxx_offset&lt;/span&gt; &lt;span class="err"&gt;等&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 日期
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;login_at&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;create_date&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;logout_time&lt;/span&gt; &lt;span class="err"&gt;等&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 布尔
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;is_done&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;is_vip&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;protected&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;can_read&lt;/span&gt; &lt;span class="err"&gt;等&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// URL
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;user_avatar_url&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;thumb_url&lt;/span&gt; &lt;span class="err"&gt;等&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 数组
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;profiles&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;thumb_imgs&lt;/span&gt; &lt;span class="err"&gt;等&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="空值空字段的处理"&gt;&lt;a href="#%e7%a9%ba%e5%80%bc%e7%a9%ba%e5%ad%97%e6%ae%b5%e7%9a%84%e5%a4%84%e7%90%86" class="header-anchor"&gt;&lt;/a&gt;空值、空字段的处理
&lt;/h3&gt;&lt;p&gt;空值、空字段的处理也是比较容易出问题。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;统一空值用null&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;除了布尔类型的，其余的空值统一用&lt;code&gt;null&lt;/code&gt;表示，客户端保证每种字段的&lt;code&gt;null&lt;/code&gt;可以被正常处理。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;给不同类型设置默认空值&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;除了&lt;code&gt;null&lt;/code&gt;，还可以对字段设置“默认值”，如数字就是&lt;code&gt;0&lt;/code&gt;，字符串就是空字符串&lt;code&gt;&amp;quot;&amp;quot;&lt;/code&gt;，数组就是空数组&lt;code&gt;[]&lt;/code&gt;，对象就是空对象&lt;code&gt;{}&lt;/code&gt;，这样有个好处就是可以避免很多客户端（Java、OC）处理空值（Null、nil、null）产生的异常。但是危害就是容易语义不明。还是要根据具体业务、前后端约定而定。&lt;/p&gt;
&lt;p&gt;以前写过一篇&lt;a class="link" href="http://tutuge.me/2015/07/08/fill-nil-property-of-object/" target="_blank" rel="noopener"
 &gt;用Runtime的手段填充任意NSObject对象的nil属性&lt;/a&gt;，其实就是为对象空值统一设置默认值的=。=，可以参考。&lt;/p&gt;
&lt;h3 id="布尔boolean值的处理"&gt;&lt;a href="#%e5%b8%83%e5%b0%94boolean%e5%80%bc%e7%9a%84%e5%a4%84%e7%90%86" class="header-anchor"&gt;&lt;/a&gt;布尔boolean值的处理
&lt;/h3&gt;&lt;p&gt;说实话，我见过各种布尔值表示方式，如：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-groovy" data-lang="groovy"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nl"&gt;is_login:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nl"&gt;is_login:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;true&amp;#34;&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nl"&gt;is_login:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nl"&gt;is_login:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;TRUE&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nl"&gt;is_login:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;YES&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// ...天啊
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;由于语言本身的限制、框架的处理方式，不对布尔类型的值做限制总觉得不踏实，像C、C++、Objective-C里面的布尔就是数字0和1，其它语言也都各自不一样，还有从数据库读写导致的布尔值类型不一致等。&lt;/p&gt;
&lt;p&gt;所以，如果可以的话，最好一开始就对所有请求参数、结果的布尔值类型做限定，个人觉得&lt;strong&gt;统一成数字0和1&lt;/strong&gt;最好。&lt;/p&gt;
&lt;p&gt;然后在客户端和服务端统一设置常量、宏定义，定义布尔的类型，所有的参数、结果的布尔字段全部做强制约束。&lt;/p&gt;
&lt;h3 id="时间日期字段"&gt;&lt;a href="#%e6%97%b6%e9%97%b4%e6%97%a5%e6%9c%9f%e5%ad%97%e6%ae%b5" class="header-anchor"&gt;&lt;/a&gt;时间、日期字段
&lt;/h3&gt;&lt;p&gt;时间的处理也是非常容易出错的，特别是遇上时区转换的时候。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;强制GMT/UTC时间戳&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;一种做法就是强制所有时间参数只能传Unix时间戳，也就是标准GMT/UTC时间戳，然后由各自的客户端根据自己的时区、显示要求做处理后显示。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-dts" data-lang="dts"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 从服务器接收的时间数据
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nl"&gt;login_at&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1462068610&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 根据时区、显示要求转换，如北京时间
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;显示：&lt;/span&gt;&lt;span class="mi"&gt;2016&lt;/span&gt;&lt;span class="err"&gt;年&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="err"&gt;月&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;日下午&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;点、&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="err"&gt;天前等&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这样的话，客户端、服务端存储、读取时间都相当于处理纯数字。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;使用ISO 8601带时区的时间日期字符串&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;使用Unix时间戳有个坏处，就是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;最早只能到&lt;code&gt;1970/1/1 0:0:0&lt;/code&gt;GMT时间，一旦需求早于这个时间，时间戳就成了负数=。=&lt;/li&gt;
&lt;li&gt;不方便人阅读。调试API的时候，开发人员不能直观看出具体时间，很不方便&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所以，可以按照&lt;a class="link" href="https://en.wikipedia.org/wiki/ISO_8601" target="_blank" rel="noopener"
 &gt;ISO 8601&lt;/a&gt;标准，用字符串保存、传输时间。&lt;/p&gt;
&lt;p&gt;如果以&lt;code&gt;YYYY-MM-DDThh:mm:ssTZD&lt;/code&gt;格式为准, 时间的形式就是&lt;code&gt;1997-07-16T19:20:30+01:00&lt;/code&gt;，保存了时区信息，也方便阅读。&lt;/p&gt;
&lt;h3 id="type类型的处理"&gt;&lt;a href="#type%e7%b1%bb%e5%9e%8b%e7%9a%84%e5%a4%84%e7%90%86" class="header-anchor"&gt;&lt;/a&gt;type类型的处理
&lt;/h3&gt;&lt;p&gt;API数据中免不了各种类型字段，如用户类型&lt;code&gt;user_type&lt;/code&gt;、登录类型&lt;code&gt;login_type&lt;/code&gt;等，类型的表示也可以分为数字、字符串两种。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;数字表示类型&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这个应该是最直接的方式了，客户端和服务端共同维护某个API下、某个数据类型中的type常量，靠文档约束。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;字符串表示类型&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;数字的类型毕竟不利于直观阅读，如果可以的话，用字符串也是不错的，当然坏处就是代码里面就不能用&lt;code&gt;Switch&lt;/code&gt;语句了（除了强大的Swift=。=）&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-dts" data-lang="dts"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;// 如登录类型，QQ、微信、微博等
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nl"&gt;login_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;qq&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nl"&gt;login_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;wechat&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nl"&gt;login_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#34;sina_weibo&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id="完整的url"&gt;&lt;a href="#%e5%ae%8c%e6%95%b4%e7%9a%84url" class="header-anchor"&gt;&lt;/a&gt;完整的URL
&lt;/h3&gt;&lt;p&gt;API里面的数据也会有URL类型的，一般来说如用户的头像、各种图片、音频等资源，都是以URL链接的形式返回的。&lt;/p&gt;
&lt;p&gt;返回的URL一定要“完整”，主要指的是不要忘记URL里面的&lt;strong&gt;协议&lt;/strong&gt;部分，也就是&lt;code&gt;scheme&lt;/code&gt;部分。&lt;/p&gt;
&lt;p&gt;像&lt;code&gt;tutuge.me/imgs/1.jpg&lt;/code&gt;这种URL值，就是不完整的，没有指明网络协议，难道靠猜=。=
应该是&lt;code&gt;http://tutuge.me/imgs/1.jpg&lt;/code&gt;。&lt;/p&gt;
&lt;h2 id="总结"&gt;&lt;a href="#%e6%80%bb%e7%bb%93" class="header-anchor"&gt;&lt;/a&gt;总结
&lt;/h2&gt;&lt;p&gt;嗯，规范非常重要。:-D&lt;/p&gt;</description></item><item><title>RPC框架Thrift例子-PHP调用C++后端程序</title><link>https://tutuge.me/2015/04/19/thrift-example-cpp-and-php/</link><pubDate>Sun, 19 Apr 2015 09:04:56 +0000</pubDate><guid>https://tutuge.me/2015/04/19/thrift-example-cpp-and-php/</guid><description>&lt;img src="https://tutuge.me/assets/2015/04/19/thrift-example-cpp-and-php/blog_thrift_example_cpp_and_php_1.jpg" alt="Featured image of post RPC框架Thrift例子-PHP调用C++后端程序" /&gt;&lt;h2 id="更新"&gt;&lt;a href="#%e6%9b%b4%e6%96%b0" class="header-anchor"&gt;&lt;/a&gt;更新
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;2016-02-22: Response对象不用主动创建。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="前言"&gt;&lt;a href="#%e5%89%8d%e8%a8%80" class="header-anchor"&gt;&lt;/a&gt;前言
&lt;/h2&gt;&lt;p&gt;前段时间用了一下Facebook的开源RPC框架Thrift，做PHP客户端调用C++后端程序，真心觉得Thrift不错！&lt;/p&gt;
&lt;p&gt;本文项目地址：&lt;a class="link" href="https://github.com/zekunyan/ThriftDemo_PHP_CPP" target="_blank" rel="noopener"
 &gt;https://github.com/zekunyan/ThriftDemo_PHP_CPP&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;先看看本文的例子示意图：&lt;/p&gt;
&lt;p&gt;&lt;img alt="通信示意图" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://tutuge.me/assets/2015/04/19/thrift-example-cpp-and-php/blog_thrift_example_cpp_and_php_1.jpg"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;流程&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;PHP客户端发起请求，请求参数是“Request”类型，里面有studentID参数。&lt;/li&gt;
&lt;li&gt;CPP服务端收到请求返回数据，返回类型为“Response”，里面包含了student的信息，此处只是简单的示例。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="定义"&gt;&lt;a href="#%e5%ae%9a%e4%b9%89" class="header-anchor"&gt;&lt;/a&gt;定义
&lt;/h2&gt;&lt;h3 id="什么是rpc"&gt;&lt;a href="#%e4%bb%80%e4%b9%88%e6%98%afrpc" class="header-anchor"&gt;&lt;/a&gt;什么是RPC
&lt;/h3&gt;&lt;p&gt;远程过程调用（英语：Remote Procedure Call，缩写为 RPC）是一个计算机通信协议。该协议允许运行于一台计算机的程序调用另一台计算机的子程序，而程序员无需额外地为这个交互作用编程。 – 维基百科 - &lt;a class="link" href="http://zh.wikipedia.org/wiki/%E9%81%A0%E7%A8%8B%E9%81%8E%E7%A8%8B%E8%AA%BF%E7%94%A8" target="_blank" rel="noopener"
 &gt;远程过程调用&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;通俗点讲，就是跨计算机、跨网络调用。&lt;/p&gt;
&lt;h3 id="什么是thrift"&gt;&lt;a href="#%e4%bb%80%e4%b9%88%e6%98%afthrift" class="header-anchor"&gt;&lt;/a&gt;什么是Thrift
&lt;/h3&gt;&lt;p&gt;Apache Thrift 是Facebook实现的一种高效的、支持多种编程语言的远程服务调用(RPC)的框架。它采用接口描述语言定义并创建服务，支持可扩展的跨语言服务开发，所包含的代码生成引擎可以在多种语言中，如 C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, Smalltalk 等创建高效的、无缝的服务，其传输数据采用二进制格式，相对 XML 和 JSON 体积更小，对于高并发、大数据量和多语言的环境更有优势。 – &lt;a class="link" href="https://www.ibm.com/developerworks/cn/java/j-lo-apachethrift/" target="_blank" rel="noopener"
 &gt;Apache Thrift - 可伸缩的跨语言服务开发框架&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="开发流程"&gt;&lt;a href="#%e5%bc%80%e5%8f%91%e6%b5%81%e7%a8%8b" class="header-anchor"&gt;&lt;/a&gt;开发流程
&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;配置环境。C++的如CMake、make、g++；PHP的如php、php-fpm、Apache（Nginx）。&lt;/li&gt;
&lt;li&gt;根据需求，编写thrift接口定义文件（IDL定义文件）。&lt;/li&gt;
&lt;li&gt;使用thrift程序，为不同的语言生成代码。&lt;/li&gt;
&lt;li&gt;根据需求，修改生成的代码（主要是Server端），编写实际的业务逻辑。&lt;/li&gt;
&lt;li&gt;编译、部署。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="thrift的接口定义文件"&gt;&lt;a href="#thrift%e7%9a%84%e6%8e%a5%e5%8f%a3%e5%ae%9a%e4%b9%89%e6%96%87%e4%bb%b6" class="header-anchor"&gt;&lt;/a&gt;Thrift的接口定义文件
&lt;/h2&gt;&lt;p&gt;在利用Thrift开发的过程中，重点就是编写接口定义文件。
一般来说，接口定义文件决定了RPC过程中的通信数据结构、通信接口定义等。&lt;/p&gt;
&lt;p&gt;总的来说，thrift的接口定义语法类似于C语言，包含了struct、enum、map、list等基础数据结构，同时支持大部分基本数据类型，如32位整型“i32”等。&lt;/p&gt;
&lt;p&gt;详细的接口定义请参考：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="http://thrift.apache.org/docs/idl" target="_blank" rel="noopener"
 &gt;Thrift interface description language&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://git-wip-us.apache.org/repos/asf?p=thrift.git;a=blob_plain;f=tutorial/tutorial.thrift" target="_blank" rel="noopener"
 &gt;example.thrift&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;看看本例子中的定义文件“TTG.thrift”：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-thrift" data-lang="thrift"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;namespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;cpp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TTG&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kn"&gt;namespace&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;php&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TTG&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;enum&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;ResponseState&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StateOk&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StateError&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;StateEmpty&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Request&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;i32&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;studentID&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;i32&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;studentID&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;list&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;infos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ResponseState&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;TTGService&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;getStudentInfo&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol&gt;
&lt;li&gt;先定义命名空间，尽量减少命名冲突。&lt;/li&gt;
&lt;li&gt;Request类型：PHP客户端请求的数据类型。&lt;/li&gt;
&lt;li&gt;Response类型：CPP服务端返回的数据类型。&lt;/li&gt;
&lt;li&gt;ResponseState枚举：定义返回的状态。&lt;/li&gt;
&lt;li&gt;TTGService：服务接口定义。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="生成对应语言的代码"&gt;&lt;a href="#%e7%94%9f%e6%88%90%e5%af%b9%e5%ba%94%e8%af%ad%e8%a8%80%e7%9a%84%e4%bb%a3%e7%a0%81" class="header-anchor"&gt;&lt;/a&gt;生成对应语言的代码！
&lt;/h2&gt;&lt;p&gt;是的，生成代码！这是我觉得Thrift框架最“神奇”的地方。我们只需要执行几条命令，就可以根据接口定义文件“生成”对应语言的代码。然后我们只需要将对应的业务逻辑加入到生成的代码中即可。&lt;/p&gt;
&lt;p&gt;如生成CPP服务端的代码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-ada" data-lang="ada"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;thrift&lt;/span&gt; &lt;span class="c1"&gt;--gen cpp TTG.thrift
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后就会生成如下代码。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-stylus" data-lang="stylus"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;TTGService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;cpp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;TTGService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;h&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;TTGService_server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;skeleton&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;cpp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;TTG_constants&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;cpp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;TTG_constants&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;h&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;TTG_types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;cpp&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="err"&gt;TTG_types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;h&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="根据需要修改生成的代码"&gt;&lt;a href="#%e6%a0%b9%e6%8d%ae%e9%9c%80%e8%a6%81%e4%bf%ae%e6%94%b9%e7%94%9f%e6%88%90%e7%9a%84%e4%bb%a3%e7%a0%81" class="header-anchor"&gt;&lt;/a&gt;根据需要修改生成的代码
&lt;/h2&gt;&lt;p&gt;生成CPP、PHP端的代码以后，我们就可以根据需要修改、添加业务代码。&lt;/p&gt;
&lt;h3 id="cpp服务端"&gt;&lt;a href="#cpp%e6%9c%8d%e5%8a%a1%e7%ab%af" class="header-anchor"&gt;&lt;/a&gt;CPP服务端
&lt;/h3&gt;&lt;p&gt;在生成CPP的代码时，会生成一个“TTGService_server.skeleton.cpp”文件，这个就是我们的CPP服务端的代码“架子”。其中重点如下：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;//实现调用的接口
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TTGServiceHandler&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="k"&gt;virtual&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;TTGServiceIf&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;TTGServiceHandler&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// Your initialization goes here
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;//接口实现部分，实现getStudentInfo这个接口的具体细节，如根据request创建、返回对应的response
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;getStudentInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;_return&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// Your implementation goes here
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;getStudentInfo&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;//...
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;我们将其改成：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-objectivec" data-lang="objectivec"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;getStudentInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Response&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;_return&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 输出请求参数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;cout&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Request: &amp;#34;&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;studentID&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;endl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;//填充数据，Response对象不用主动创建，进入函数时已经创建好了
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;_return&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;studentID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;studentID&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;_return&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;&amp;#34;tutuge&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;_return&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;infos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Info 1&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;_return&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;infos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;push_back&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#34;Info 2&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;_return&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ResponseState&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;StateOk&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;至此，CPP服务端的编写就完成了，接下来我们只需要编译、链接，执行最终生成的可执行文件即可。&lt;/p&gt;
&lt;h3 id="php客户端"&gt;&lt;a href="#php%e5%ae%a2%e6%88%b7%e7%ab%af" class="header-anchor"&gt;&lt;/a&gt;PHP客户端
&lt;/h3&gt;&lt;p&gt;PHP客户端的编写比较简单，直接参考代码吧：&lt;a class="link" href="https://github.com/zekunyan/ThriftDemo_PHP_CPP/blob/master/PHP/client.php" target="_blank" rel="noopener"
 &gt;https://github.com/zekunyan/ThriftDemo_PHP_CPP/blob/master/PHP/client.php&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="编译链接运行"&gt;&lt;a href="#%e7%bc%96%e8%af%91%e9%93%be%e6%8e%a5%e8%bf%90%e8%a1%8c" class="header-anchor"&gt;&lt;/a&gt;编译、链接，运行
&lt;/h2&gt;&lt;p&gt;用CMake，或者直接编写makefile均可，保证Thrift装好就行了。&lt;/p&gt;
&lt;p&gt;直接运行最后生成的可执行文件TTG.run即可。&lt;/p&gt;
&lt;p&gt;从浏览器，或者直接运行client.php，即可看到如下输出：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;object(TTG\Response)[9]
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; public &amp;#39;studentID&amp;#39; =&amp;gt; int 100
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; public &amp;#39;name&amp;#39; =&amp;gt; string &amp;#39;tutuge&amp;#39; (length=6)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; public &amp;#39;infos&amp;#39; =&amp;gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; array (size=2)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 0 =&amp;gt; string &amp;#39;Info 1&amp;#39; (length=6)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 1 =&amp;gt; string &amp;#39;Info 2&amp;#39; (length=6)
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; public &amp;#39;state&amp;#39; =&amp;gt; int 0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="总结"&gt;&lt;a href="#%e6%80%bb%e7%bb%93" class="header-anchor"&gt;&lt;/a&gt;总结
&lt;/h2&gt;&lt;p&gt;Thrift是个好东西！就是文档好少=。=&lt;/p&gt;
&lt;h2 id="参考"&gt;&lt;a href="#%e5%8f%82%e8%80%83" class="header-anchor"&gt;&lt;/a&gt;参考
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="http://thrift.apache.org/" target="_blank" rel="noopener"
 &gt;Apache Thrift&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="http://thrift.apache.org/tutorial/php" target="_blank" rel="noopener"
 &gt;Thrift PHP Tutorial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="http://thrift.apache.org/tutorial/cpp" target="_blank" rel="noopener"
 &gt;Thrift C++ Tutorial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="http://en.wikipedia.org/wiki/Apache_Thrift" target="_blank" rel="noopener"
 &gt;Apache Thrift&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://www.ibm.com/developerworks/cn/java/j-lo-apachethrift/" target="_blank" rel="noopener"
 &gt;Apache Thrift - 可伸缩的跨语言服务开发框架&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>