3.1.coap.md.html 53 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601
  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  2. <html xmlns="http://www.w3.org/1999/xhtml">
  3. <head>
  4. <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  5. <meta http-equiv="Content-Style-Type" content="text/css" />
  6. <meta name="generator" content="pandoc" />
  7. <title></title>
  8. <style type="text/css">code{white-space: pre;}</style>
  9. <style type="text/css">
  10. div.sourceCode { overflow-x: auto; }
  11. table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode {
  12. margin: 0; padding: 0; vertical-align: baseline; border: none; }
  13. table.sourceCode { width: 100%; line-height: 100%; }
  14. td.lineNumbers { text-align: right; padding-right: 4px; padding-left: 4px; color: #aaaaaa; border-right: 1px solid #aaaaaa; }
  15. td.sourceCode { padding-left: 5px; }
  16. code > span.kw { color: #007020; font-weight: bold; } /* Keyword */
  17. code > span.dt { color: #902000; } /* DataType */
  18. code > span.dv { color: #40a070; } /* DecVal */
  19. code > span.bn { color: #40a070; } /* BaseN */
  20. code > span.fl { color: #40a070; } /* Float */
  21. code > span.ch { color: #4070a0; } /* Char */
  22. code > span.st { color: #4070a0; } /* String */
  23. code > span.co { color: #60a0b0; font-style: italic; } /* Comment */
  24. code > span.ot { color: #007020; } /* Other */
  25. code > span.al { color: #ff0000; font-weight: bold; } /* Alert */
  26. code > span.fu { color: #06287e; } /* Function */
  27. code > span.er { color: #ff0000; font-weight: bold; } /* Error */
  28. code > span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
  29. code > span.cn { color: #880000; } /* Constant */
  30. code > span.sc { color: #4070a0; } /* SpecialChar */
  31. code > span.vs { color: #4070a0; } /* VerbatimString */
  32. code > span.ss { color: #bb6688; } /* SpecialString */
  33. code > span.im { } /* Import */
  34. code > span.va { color: #19177c; } /* Variable */
  35. code > span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
  36. code > span.op { color: #666666; } /* Operator */
  37. code > span.bu { } /* BuiltIn */
  38. code > span.ex { } /* Extension */
  39. code > span.pp { color: #bc7a00; } /* Preprocessor */
  40. code > span.at { color: #7d9029; } /* Attribute */
  41. code > span.do { color: #ba2121; font-style: italic; } /* Documentation */
  42. code > span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
  43. code > span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
  44. code > span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
  45. </style>
  46. <link rel="stylesheet" href="css/vendor.css" type="text/css" />
  47. </head>
  48. <body>
  49. <html xmlns="http://www.w3.org/1999/xhtml" xmlns:wb="http://open.weibo.com/wb" >
  50. <head>
  51. <title>一步步搭建物联网系统(教你设计物联网系统)</title>
  52. <meta name="keywords" content="设计物联网系统,物联网系统设计">
  53. <meta name="description" content="一份关于如何设计物联网系统的文档">
  54. <link rel="stylesheet" href="../css/vendor.css" />
  55. </head>
  56. <body class="container inner wrap">
  57. <h1>一步步搭建物联网系统(教你设计物联网系统)</h1>
  58. </body>
  59. </html>
  60. <div id="TOC">
  61. <ul>
  62. <li><a href="#restful的coap协议"><span class="toc-section-number">1</span> RESTful的CoAP协议</a><ul>
  63. <li><a href="#coap-嵌入式系统的rest"><span class="toc-section-number">1.1</span> CoAP: 嵌入式系统的REST</a></li>
  64. <li><a href="#coap-命令行工具"><span class="toc-section-number">1.2</span> CoAP 命令行工具</a><ul>
  65. <li><a href="#node-coap-cli"><span class="toc-section-number">1.2.1</span> Node CoAP CLI</a></li>
  66. <li><a href="#libcoap"><span class="toc-section-number">1.2.2</span> libcoap</a></li>
  67. <li><a href="#firefox-copper"><span class="toc-section-number">1.2.3</span> Firefox Copper</a></li>
  68. </ul></li>
  69. <li><a href="#coap-helloworld"><span class="toc-section-number">1.3</span> CoAP Hello,World</a></li>
  70. <li><a href="#coap-数据库查询"><span class="toc-section-number">1.4</span> CoAP 数据库查询</a><ul>
  71. <li><a href="#node-module"><span class="toc-section-number">1.4.1</span> Node Module</a></li>
  72. <li><a href="#node-sqlite3"><span class="toc-section-number">1.4.2</span> Node-Sqlite3</a></li>
  73. <li><a href="#查询数据"><span class="toc-section-number">1.4.3</span> 查询数据</a></li>
  74. </ul></li>
  75. <li><a href="#coap-block"><span class="toc-section-number">1.5</span> CoAP Block</a><ul>
  76. <li><a href="#coap-post"><span class="toc-section-number">1.5.1</span> CoAP POST</a></li>
  77. <li><a href="#coap-content-types"><span class="toc-section-number">1.5.2</span> CoAP Content Types</a></li>
  78. </ul></li>
  79. <li><a href="#coap-json"><span class="toc-section-number">1.6</span> CoAP JSON</a></li>
  80. </ul></li>
  81. </ul>
  82. </div>
  83. <h1 id="restful的coap协议"><span class="header-section-number">1</span> RESTful的CoAP协议</h1>
  84. <h2 id="coap-嵌入式系统的rest"><span class="header-section-number">1.1</span> CoAP: 嵌入式系统的REST</h2>
  85. <p>引自维基百科上的介绍,用的是谷歌翻译。。。</p>
  86. <blockquote>
  87. <p>受约束的应用协议(COAP)是一种软件协议旨在以非常简单的电子设备,使他们能够在互联网上进行交互式通信中使用。它特别针对小型低功率传感器,开关,阀门和需要被控制或监督远程,通过标准的Internet网络类似的组件。 COAP是一个应用层协议,该协议是用于在资源受限的网络连接设备,例如无线传感器网络节点使用。 COAP被设计为容易地转换为HTTP与Web简化集成,同时也能满足特殊的要求,例如多播支持,非常低的开销,和简单性。多播,低开销,以及简单性是因特网极其重要物联网(IOT)和机器对机器(M2M)设备,这往往是积重难返,有太多的内存和电源,比传统的互联网设备有。因此,效率是非常重要的。 COAP可以在支持UDP或UDP的模拟大多数设备上运行。</p>
  88. </blockquote>
  89. <p>简单地来说,CoAP是简化了HTTP协议的RESTful API,因而也只提供了REST的四个方法,即PUT,GET,POST和DELETE。对于微小的资源受限,在资源受限的通信的IP的网络,HTTP不是一种可行的选择。它占用了太多的资源和太多的带宽。而对于物联网这种嵌入式设备来说,关于资源与带宽,是我们需要优先考虑的内容。</p>
  90. <ul>
  91. <li>CoAP采用了二进制报头,而不是文本报头(text header)</li>
  92. <li>CoAP降低了头的可用选项的数量。</li>
  93. <li>CoAP减少了一些HTTP的方法</li>
  94. <li>CoAP可以支持检测装置</li>
  95. </ul>
  96. <h2 id="coap-命令行工具"><span class="header-section-number">1.2</span> CoAP 命令行工具</h2>
  97. <p>为了测试测试我们的代码是否是正确工作,我们需要一个CoAP的命令行工具。目前有两个不错的工具可以使用。</p>
  98. <ul>
  99. <li>CoAP-cli,一个基于NodeJS的CoAP命令行工具,其核心是基于Node-CoAP库。</li>
  100. <li>libcooap,一个用C写的CoAP命令行工具。</li>
  101. <li>FireFox Copper, 一个Firefox的插件。</li>
  102. </ul>
  103. <h3 id="node-coap-cli"><span class="header-section-number">1.2.1</span> Node CoAP CLI</h3>
  104. <p>安装命令如下</p>
  105. <div class="sourceCode"><pre class="sourceCode bash"><code class="sourceCode bash"> <span class="kw">npm</span> install coap-cli -g </code></pre></div>
  106. <h4 id="coap命令行"><span class="header-section-number">1.2.1.1</span> CoAP命令行</h4>
  107. <p>在coap-cli中,一共有四个方法。分别表示REST的四种不同的方式:</p>
  108. <div class="sourceCode"><pre class="sourceCode bash"><code class="sourceCode bash"><span class="kw">Commands</span>:
  109. <span class="kw">get</span> performs a GET request
  110. <span class="kw">put</span> performs a PUT request
  111. <span class="kw">post</span> performs a POST request
  112. <span class="kw">delete</span> performs a DELETE request</code></pre></div>
  113. <p>在这里,我们用<a href="coap://vs0.inf.ethz.ch/" class="uri">coap://vs0.inf.ethz.ch/</a>来作一个简单的测试</p>
  114. <div class="sourceCode"><pre class="sourceCode bash"><code class="sourceCode bash"><span class="kw">coap</span> get coap://vs0.inf.ethz.ch/
  115. <span class="kw">(2.05)</span> <span class="kw">************************************************************</span>
  116. <span class="kw">I-D</span></code></pre></div>
  117. <p>测试一下现在的最小的物联网系统CoAP版</p>
  118. <div class="sourceCode"><pre class="sourceCode bash"><code class="sourceCode bash"><span class="kw">coap</span> get coap://iot-coap.phodal.com/id/1
  119. <span class="kw">(2.05)</span> [{<span class="st">&quot;id&quot;</span>:<span class="kw">1</span>,<span class="st">&quot;value&quot;</span>:<span class="st">&quot;is id 1&quot;</span>,<span class="st">&quot;sensors1&quot;</span>:19,<span class="st">&quot;sensors2&quot;</span>:20}]</code></pre></div>
  120. <h3 id="libcoap"><span class="header-section-number">1.2.2</span> libcoap</h3>
  121. <h4 id="mac-os-libcoap安装"><span class="header-section-number">1.2.2.1</span> mac os libcoap安装</h4>
  122. <p>Mac OS下可以直接用</p>
  123. <div class="sourceCode"><pre class="sourceCode bash"><code class="sourceCode bash"><span class="kw">brew</span> install libcoap</code></pre></div>
  124. <h4 id="ubuntu-libcoap安装"><span class="header-section-number">1.2.2.2</span> Ubuntu libcoap安装</h4>
  125. <p>Ubuntu GNU/Linux下</p>
  126. <h4 id="windows-libcoap安装"><span class="header-section-number">1.2.2.3</span> Windows libcoap安装</h4>
  127. <p>Windows 下</p>
  128. <p>安装完libcoap,我们可以直接用自带的两个命令</p>
  129. <div class="sourceCode"><pre class="sourceCode bash"><code class="sourceCode bash"><span class="kw">coap-client</span>
  130. <span class="kw">coap-server</span></code></pre></div>
  131. <p>1.用coap-server启一个CoAP服务</p>
  132. <div class="sourceCode"><pre class="sourceCode bash"><code class="sourceCode bash"><span class="kw">coap-server</span></code></pre></div>
  133. <p>2.客户端获取数据</p>
  134. <div class="sourceCode"><pre class="sourceCode bash"><code class="sourceCode bash"><span class="kw">coap-client</span> -m get coap://localhost</code></pre></div>
  135. <p>返回结果</p>
  136. <div class="sourceCode"><pre class="sourceCode bash"><code class="sourceCode bash"><span class="kw">v</span>:1 t:0 tkl:0 c:1 id:37109
  137. <span class="kw">This</span> is a test server made with libcoap (see http://libcoap.sf.net)
  138. <span class="kw">Copyright</span> (C) <span class="kw">2010--2013</span> Olaf Bergmann <span class="kw">&lt;</span>bergmann@tzi.org<span class="kw">&gt;</span></code></pre></div>
  139. <h3 id="firefox-copper"><span class="header-section-number">1.2.3</span> Firefox Copper</h3>
  140. <p>为了能访问<a href="coap://localhost/" class="uri">coap://localhost/</a>,于是我们便需要安装一个Firefox并安装一个名为Copper的插件。</p>
  141. <ol style="list-style-type: decimal">
  142. <li><p>下载地址: <a href="https://addons.mozilla.org/en-US/firefox/addon/copper-270430/" class="uri">https://addons.mozilla.org/en-US/firefox/addon/copper-270430/</a></p></li>
  143. <li><p>作为测试我们同样可以访问 <a href="coap://vs0.inf.ethz.ch:5683/" class="uri">coap://vs0.inf.ethz.ch:5683/</a></p></li>
  144. </ol>
  145. <h2 id="coap-helloworld"><span class="header-section-number">1.3</span> CoAP Hello,World</h2>
  146. <p>接着我们便开始试试做一个简单的CoAP协议的应用:</p>
  147. <p>这里用到的是一个Nodejs的扩展Node-CoAP</p>
  148. <blockquote>
  149. <p>node-coap is a client and server library for CoAP modelled after the http module.</p>
  150. </blockquote>
  151. <p>Node-CoAP是一个客户端和服务端的库用于CoAP的模块建模。创建一个package.json文件,添加这个库</p>
  152. <div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="op">{</span>
  153. <span class="st">&quot;dependencies&quot;</span><span class="op">:{</span>
  154. <span class="st">&quot;coap&quot;</span><span class="op">:</span> <span class="st">&quot;0.7.2&quot;</span>
  155. <span class="op">}</span>
  156. <span class="op">}</span></code></pre></div>
  157. <p>接着执行</p>
  158. <div class="sourceCode"><pre class="sourceCode bash"><code class="sourceCode bash"><span class="kw">npm</span> install</code></pre></div>
  159. <p>就可以安装好这个库。如果遇到权限问题,请用</p>
  160. <div class="sourceCode"><pre class="sourceCode bash"><code class="sourceCode bash"><span class="kw">sudo</span> npm install</code></pre></div>
  161. <p>接着,创建这样一个app.js</p>
  162. <div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="kw">const</span> coap <span class="op">=</span> <span class="at">require</span>(<span class="st">&#39;coap&#39;</span>)
  163. <span class="op">,</span> server <span class="op">=</span> <span class="va">coap</span>.<span class="at">createServer</span>()
  164. <span class="va">server</span>.<span class="at">on</span>(<span class="st">&#39;request&#39;</span><span class="op">,</span> <span class="kw">function</span>(req<span class="op">,</span> res) <span class="op">{</span>
  165. <span class="va">res</span>.<span class="at">end</span>(<span class="st">&#39;Hello &#39;</span> <span class="op">+</span> <span class="va">req</span>.<span class="va">url</span>.<span class="at">split</span>(<span class="st">&#39;/&#39;</span>)[<span class="dv">1</span>] <span class="op">+</span> <span class="st">&#39;</span><span class="sc">\n</span><span class="st">&#39;</span>)
  166. <span class="op">}</span>)
  167. <span class="va">server</span>.<span class="at">listen</span>(<span class="kw">function</span>() <span class="op">{</span>
  168. <span class="va">console</span>.<span class="at">log</span>(<span class="st">&#39;server started&#39;</span>)
  169. <span class="op">}</span>) </code></pre></div>
  170. <p>执行</p>
  171. <div class="sourceCode"><pre class="sourceCode bash"><code class="sourceCode bash"><span class="kw">node</span> app.js</code></pre></div>
  172. <p>便可以在浏览器上访问了,因为现在什么也没有,所以什么也不会返回。</p>
  173. <p>接着下来再创建一个client端的js,并运行之</p>
  174. <div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="kw">const</span> coap <span class="op">=</span> <span class="at">require</span>(<span class="st">&#39;coap&#39;</span>)
  175. <span class="op">,</span> req <span class="op">=</span> <span class="va">coap</span>.<span class="at">request</span>(<span class="st">&#39;coap://localhost/World&#39;</span>)
  176. <span class="va">req</span>.<span class="at">on</span>(<span class="st">&#39;response&#39;</span><span class="op">,</span> <span class="kw">function</span>(res) <span class="op">{</span>
  177. <span class="va">res</span>.<span class="at">pipe</span>(<span class="va">process</span>.<span class="at">stdout</span>)
  178. <span class="op">}</span>)
  179. <span class="va">req</span>.<span class="at">end</span>()</code></pre></div>
  180. <p>就可以在console上输出</p>
  181. <div class="sourceCode"><pre class="sourceCode bash"><code class="sourceCode bash"><span class="kw">Hello</span> World </code></pre></div>
  182. <p>也就达到了我们的目的,用CoAP协议创建一个服务,接着我们应该用它创建更多的东西,如产生JSON数据,以及RESTful。和HTTP版的最小物联网系统一样,CoAP版的最小物联网系统也是要返回JSON的。</p>
  183. <h2 id="coap-数据库查询"><span class="header-section-number">1.4</span> CoAP 数据库查询</h2>
  184. <h3 id="node-module"><span class="header-section-number">1.4.1</span> Node Module</h3>
  185. <p>这说里NodeJS Module的意义是因为我们需要在别的地方引用到db_helper这个库,也就是下一小节要的讲的内容。</p>
  186. <p>这样我们就可以在server.js类似于这样去引用这个js库。</p>
  187. <div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="kw">var</span> DBHelper <span class="op">=</span> <span class="at">require</span>(<span class="st">&#39;./db_helper.js&#39;</span>)<span class="op">;</span>
  188. <span class="va">DBHelper</span>.<span class="at">initDB</span>()<span class="op">;</span></code></pre></div>
  189. <p>而这样调用的前提是我们需要去声明这样的module,为了方便地导出函数功能调用。</p>
  190. <div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="kw">function</span> <span class="at">DBHelper</span>()<span class="op">{</span>
  191. <span class="op">}</span>
  192. <span class="va">DBHelper</span>.<span class="at">initDB</span> <span class="op">=</span> <span class="kw">function</span>()<span class="op">{};</span>
  193. <span class="va">module</span>.<span class="at">exports</span> <span class="op">=</span> DBHelper<span class="op">;</span></code></pre></div>
  194. <h3 id="node-sqlite3"><span class="header-section-number">1.4.2</span> Node-Sqlite3</h3>
  195. <p>这次我们用的是SQLite3(你可以用MySQL,出于安全考虑用SQLite3,SQLite3产生的是一个文件)。一个简单的initDB函数</p>
  196. <div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="kw">var</span> db <span class="op">=</span> <span class="kw">new</span> <span class="va">sqlite3</span>.<span class="at">Database</span>(config[<span class="st">&quot;db_name&quot;</span>])<span class="op">;</span>
  197. <span class="kw">var</span> create_table <span class="op">=</span> <span class="st">&#39;create table if not exists basic (&#39;</span> <span class="op">+</span> config[<span class="st">&quot;db_table&quot;</span>] <span class="op">+</span> <span class="st">&#39;);&#39;</span><span class="op">;</span>
  198. <span class="va">db</span>.<span class="at">serialize</span>(<span class="kw">function</span>() <span class="op">{</span>
  199. <span class="va">db</span>.<span class="at">run</span>(create_table)<span class="op">;</span>
  200. <span class="va">_</span>.<span class="at">each</span>(config[<span class="st">&quot;init_table&quot;</span>]<span class="op">,</span> <span class="kw">function</span>(insert_data) <span class="op">{</span>
  201. <span class="va">db</span>.<span class="at">run</span>(insert_data)<span class="op">;</span>
  202. <span class="op">}</span>)<span class="op">;</span>
  203. <span class="op">}</span>)<span class="op">;</span>
  204. <span class="va">db</span>.<span class="at">close</span>()<span class="op">;</span></code></pre></div>
  205. <p>首先从配置中读取db_name,接着创建table,然后调用underscore的each方法,创建几个数据。配置如下所示</p>
  206. <div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript">config <span class="op">=</span> <span class="op">{</span>
  207. <span class="st">&quot;db_name&quot;</span><span class="op">:</span> <span class="st">&quot;iot.db&quot;</span><span class="op">,</span>
  208. <span class="st">&quot;db_table&quot;</span><span class="op">:</span> <span class="st">&quot;id integer primary key, value text, sensors1 float, sensors2 float&quot;</span><span class="op">,</span>
  209. <span class="st">&quot;init_table&quot;</span><span class="op">:</span>[
  210. <span class="st">&quot;insert or replace into basic (id,value,sensors1,sensors2) VALUES (1, &#39;is id 1&#39;, 19, 20);&quot;</span><span class="op">,</span>
  211. <span class="st">&quot;insert or replace into basic (id,value,sensors1,sensors2) VALUES (2, &#39;is id 2&#39;, 20, 21);&quot;</span>
  212. ]<span class="op">,</span>
  213. <span class="st">&quot;query_table&quot;</span><span class="op">:</span><span class="st">&quot;select * from basic;&quot;</span>
  214. <span class="op">};</span></code></pre></div>
  215. <p>而之前所提到的url查询所做的事情便是</p>
  216. <div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="va">DBHelper</span>.<span class="at">urlQueryData</span> <span class="op">=</span> <span class="kw">function</span> (url<span class="op">,</span> callback) <span class="op">{</span>
  217. <span class="kw">var</span> db <span class="op">=</span> <span class="kw">new</span> <span class="va">sqlite3</span>.<span class="at">Database</span>(<span class="st">&quot;iot.db&quot;</span>)<span class="op">;</span>
  218. <span class="kw">var</span> result <span class="op">=</span> []<span class="op">;</span>
  219. <span class="va">console</span>.<span class="at">log</span>(<span class="st">&quot;SELECT * FROM basic where &quot;</span> <span class="op">+</span> <span class="va">url</span>.<span class="at">split</span>(<span class="st">&#39;/&#39;</span>)[<span class="dv">1</span>] <span class="op">+</span> <span class="st">&quot;=&quot;</span> <span class="op">+</span> <span class="va">url</span>.<span class="at">split</span>(<span class="st">&#39;/&#39;</span>)[<span class="dv">2</span>])<span class="op">;</span>
  220. <span class="va">db</span>.<span class="at">all</span>(<span class="st">&quot;SELECT * FROM basic where &quot;</span> <span class="op">+</span> <span class="va">url</span>.<span class="at">split</span>(<span class="st">&#39;/&#39;</span>)[<span class="dv">1</span>] <span class="op">+</span> <span class="st">&quot;=&quot;</span> <span class="op">+</span> <span class="va">url</span>.<span class="at">split</span>(<span class="st">&#39;/&#39;</span>)[<span class="dv">2</span>]<span class="op">,</span> <span class="kw">function</span>(err<span class="op">,</span> rows) <span class="op">{</span>
  221. <span class="va">db</span>.<span class="at">close</span>()<span class="op">;</span>
  222. <span class="at">callback</span>(<span class="va">JSON</span>.<span class="at">stringify</span>(rows))<span class="op">;</span>
  223. <span class="op">}</span>)<span class="op">;</span>
  224. <span class="op">};</span></code></pre></div>
  225. <p>将URL传进来,便解析这个参数,接着再放到数据库中查询,再回调回结果。这样我们就可以构成之前所说的查询功能,而我们所谓的post功能似乎也可以用同样的方法加进去。</p>
  226. <h3 id="查询数据"><span class="header-section-number">1.4.3</span> 查询数据</h3>
  227. <p>简单地记录一下在IoT-CoAP中一次获取数据地过程。</p>
  228. <p>先看看在示例中的Get.js的代码,这关乎在后面server端的代码。</p>
  229. <div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="kw">const</span> coap <span class="op">=</span> <span class="at">require</span>(<span class="st">&#39;coap&#39;</span>)
  230. <span class="op">,</span>requestURI <span class="op">=</span> <span class="st">&#39;coap://localhost/&#39;</span>
  231. <span class="op">,</span>url <span class="op">=</span> <span class="at">require</span>(<span class="st">&#39;url&#39;</span>).<span class="at">parse</span>(requestURI <span class="op">+</span> <span class="st">&#39;id/1/&#39;</span>)
  232. <span class="op">,</span>req <span class="op">=</span> <span class="va">coap</span>.<span class="at">request</span>(url)
  233. <span class="op">,</span>bl <span class="op">=</span> <span class="at">require</span>(<span class="st">&#39;bl&#39;</span>)<span class="op">;</span>
  234. <span class="va">req</span>.<span class="at">setHeader</span>(<span class="st">&quot;Accept&quot;</span><span class="op">,</span> <span class="st">&quot;application/json&quot;</span>)<span class="op">;</span>
  235. <span class="va">req</span>.<span class="at">on</span>(<span class="st">&#39;response&#39;</span><span class="op">,</span> <span class="kw">function</span>(res) <span class="op">{</span>
  236. <span class="va">res</span>.<span class="at">pipe</span>(<span class="at">bl</span>(<span class="kw">function</span>(err<span class="op">,</span> data) <span class="op">{</span>
  237. <span class="kw">var</span> json <span class="op">=</span> <span class="va">JSON</span>.<span class="at">parse</span>(data)<span class="op">;</span>
  238. <span class="va">console</span>.<span class="at">log</span>(json)<span class="op">;</span>
  239. <span class="op">}</span>))<span class="op">;</span>
  240. <span class="op">}</span>)<span class="op">;</span>
  241. <span class="va">req</span>.<span class="at">end</span>()<span class="op">;</span></code></pre></div>
  242. <p>const定义数据的方法,和我们在其他语言中有点像。只是这的const主要是为了程序的健壮型,减少程序出错,当然这不是javascript的用法。</p>
  243. <p>我们构建了一个请求的URL</p>
  244. <div class="sourceCode"><pre class="sourceCode bash"><code class="sourceCode bash"><span class="kw">coap</span>://localhost/id/1/</code></pre></div>
  245. <p>我们对我们的请求添加了一个Header,内容是Accept,值是’application/json’也就是JSON格式。接着,便是等待请求回来,再处理返回的内容。</p>
  246. <p><strong>判断请求的方法</strong></p>
  247. <p>在这里先把一些无关的代码删除掉,并保证其能工作,so,下面就是简要的逻辑代码。</p>
  248. <div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="kw">var</span> coap <span class="op">=</span> <span class="at">require</span>(<span class="st">&#39;coap&#39;</span>)<span class="op">;</span>
  249. <span class="kw">var</span> server <span class="op">=</span> <span class="va">coap</span>.<span class="at">createServer</span>(<span class="op">{}</span>)<span class="op">;</span>
  250. <span class="kw">var</span> request_handler <span class="op">=</span> <span class="at">require</span>(<span class="st">&#39;./request_handler.js&#39;</span>)<span class="op">;</span>
  251. <span class="va">server</span>.<span class="at">on</span>(<span class="st">&#39;request&#39;</span><span class="op">,</span> <span class="kw">function</span>(req<span class="op">,</span> res) <span class="op">{</span>
  252. <span class="cf">switch</span>(<span class="va">req</span>.<span class="at">method</span>)<span class="op">{</span>
  253. <span class="cf">case</span> <span class="st">&quot;GET&quot;</span><span class="op">:</span> <span class="va">request_handler</span>.<span class="at">getHandler</span>(req<span class="op">,</span> res)<span class="op">;</span>
  254. <span class="cf">break</span><span class="op">;</span>
  255. <span class="op">}</span>
  256. <span class="op">}</span>)<span class="op">;</span>
  257. <span class="va">server</span>.<span class="at">listen</span>(<span class="kw">function</span>() <span class="op">{</span>
  258. <span class="va">console</span>.<span class="at">log</span>(<span class="st">&#39;server started&#39;</span>)<span class="op">;</span>
  259. <span class="op">}</span>)<span class="op">;</span></code></pre></div>
  260. <p>创建一个CoAP服务,判断req.method,也就是请求的方法,如果是GET的话,就调用request_handler.getHandler(req, res)。而在getHandler里,判断了下请求的Accept</p>
  261. <div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="va">request_helper</span>.<span class="at">getHandler</span> <span class="op">=</span> <span class="kw">function</span>(req<span class="op">,</span> res) <span class="op">{</span>
  262. <span class="cf">switch</span> (<span class="va">req</span>.<span class="at">headers</span>[<span class="st">&#39;Accept&#39;</span>]) <span class="op">{</span>
  263. <span class="cf">case</span> <span class="st">&quot;application/json&quot;</span><span class="op">:</span>
  264. <span class="va">qh</span>.<span class="at">returnJSON</span>(req<span class="op">,</span> res)<span class="op">;</span>
  265. <span class="cf">break</span><span class="op">;</span>
  266. <span class="cf">case</span> <span class="st">&quot;application/xml&quot;</span><span class="op">:</span>
  267. <span class="va">qh</span>.<span class="at">returnXML</span>(req<span class="op">,</span> res)<span class="op">;</span>
  268. <span class="cf">break</span><span class="op">;</span>
  269. <span class="op">}</span>
  270. <span class="op">};</span></code></pre></div>
  271. <p>如果是json刚调用returnJSON,</p>
  272. <p><strong>Database与回调</strong></p>
  273. <p>而这里为了处理回调函数刚分为了两部分</p>
  274. <div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="va">query_helper</span>.<span class="at">returnJSON</span> <span class="op">=</span> <span class="kw">function</span>(req<span class="op">,</span> res) <span class="op">{</span>
  275. <span class="va">DBHelper</span>.<span class="at">urlQueryData</span>(<span class="va">req</span>.<span class="at">url</span><span class="op">,</span> <span class="kw">function</span> (result) <span class="op">{</span>
  276. <span class="va">QueryData</span>.<span class="at">returnJSON</span>(result<span class="op">,</span> res)<span class="op">;</span>
  277. <span class="op">}</span>)<span class="op">;</span>
  278. <span class="op">};</span></code></pre></div>
  279. <p>而这里只是调用了</p>
  280. <div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="va">DBHelper</span>.<span class="at">urlQueryData</span> <span class="op">=</span> <span class="kw">function</span> (url<span class="op">,</span> callback) <span class="op">{</span>
  281. <span class="kw">var</span> db <span class="op">=</span> <span class="kw">new</span> <span class="va">sqlite3</span>.<span class="at">Database</span>(config[<span class="st">&quot;db_name&quot;</span>])<span class="op">;</span>
  282. <span class="va">console</span>.<span class="at">log</span>(<span class="st">&quot;SELECT * FROM basic where &quot;</span> <span class="op">+</span> <span class="va">url</span>.<span class="at">split</span>(<span class="st">&#39;/&#39;</span>)[<span class="dv">1</span>] <span class="op">+</span> <span class="st">&quot;=&quot;</span> <span class="op">+</span> <span class="va">url</span>.<span class="at">split</span>(<span class="st">&#39;/&#39;</span>)[<span class="dv">2</span>])<span class="op">;</span>
  283. <span class="va">db</span>.<span class="at">all</span>(<span class="st">&quot;SELECT * FROM basic where &quot;</span> <span class="op">+</span> <span class="va">url</span>.<span class="at">split</span>(<span class="st">&#39;/&#39;</span>)[<span class="dv">1</span>] <span class="op">+</span> <span class="st">&quot;=&quot;</span> <span class="op">+</span> <span class="va">url</span>.<span class="at">split</span>(<span class="st">&#39;/&#39;</span>)[<span class="dv">2</span>]<span class="op">,</span> <span class="kw">function</span>(err<span class="op">,</span> rows) <span class="op">{</span>
  284. <span class="va">db</span>.<span class="at">close</span>()<span class="op">;</span>
  285. <span class="at">callback</span>(<span class="va">JSON</span>.<span class="at">stringify</span>(rows))<span class="op">;</span>
  286. <span class="op">}</span>)<span class="op">;</span>
  287. <span class="op">};</span></code></pre></div>
  288. <p>这里调用了node sqlite3去查询对应id的数据,用回调处理了数据无法到外部的问题,而上面的returnJSON则只是返回最后的结果,code以及其他的内容。</p>
  289. <div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="va">QueryData</span>.<span class="at">returnJSON</span> <span class="op">=</span> <span class="kw">function</span>(result<span class="op">,</span> res) <span class="op">{</span>
  290. <span class="cf">if</span> (<span class="va">result</span>.<span class="at">length</span> <span class="op">==</span> <span class="dv">2</span>) <span class="op">{</span>
  291. <span class="va">res</span>.<span class="at">code</span> <span class="op">=</span> <span class="st">&#39;4.04&#39;</span><span class="op">;</span>
  292. <span class="va">res</span>.<span class="at">end</span>(<span class="va">JSON</span>.<span class="at">stringify</span>(<span class="op">{</span>
  293. <span class="dt">error</span><span class="op">:</span> <span class="st">&quot;Not Found&quot;</span>
  294. <span class="op">}</span>))<span class="op">;</span>
  295. <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span>
  296. <span class="va">res</span>.<span class="at">code</span> <span class="op">=</span> <span class="st">&#39;2.05&#39;</span><span class="op">;</span>
  297. <span class="va">res</span>.<span class="at">end</span>(result)<span class="op">;</span>
  298. <span class="op">}</span>
  299. <span class="op">};</span></code></pre></div>
  300. <p>当resulst的结果为空时,返回一个404,因为没有数据。这样我们就构成了整个的链,再一步步返回结果。</p>
  301. <p>在<a href="https://github.com/phodal/iot-coap">IoT-CoAP</a>中我们使用到了一个Block2的东西,于是便整理相关的一些资料,作一个简单的介绍,以及在代码中的使用。</p>
  302. <h2 id="coap-block"><span class="header-section-number">1.5</span> CoAP Block</h2>
  303. <p>CoAP是一个RESTful传输协议用于受限设备的节点和网络。基本的CoAP消息是一个不错的选择对于小型载荷如</p>
  304. <ul>
  305. <li>温度传感器</li>
  306. <li>灯光开关</li>
  307. <li>楼宇自动化设备</li>
  308. </ul>
  309. <p>然而,有时我们的应用需要传输更大的有效载荷,如——更新固件。与HTTP,TCP做繁重工作将大型有效载荷分成多个数据包,并确保他们所有到达并以正确的顺序被处理。</p>
  310. <p>CoAP是同UDP与DLTS一样是基于数据报传输的,这限制了资源表示(resource representation)的最大大小,使得传输不需要太多的分割。虽然UDP支持通过IP分片传输更大的有效载荷,且仅限于64KiB,更重要的是,并没有真正很好地约束应用和网络。</p>
  311. <p>而不是依赖于IP分片,这种规范基本COAP了对“块”选项,用于传输信息从多个资源区块的请求 - 响应对。在许多重要的情况下,阻止使服务器能够真正无状态:服务器可以处理每块分开传输,而无需建立连接以前的数据块传输的其他服务器端内存。</p>
  312. <p>综上所述,块(Block)选项提供了传送一个最小的在分块的方式更大的陈述。</p>
  313. <h3 id="coap-post"><span class="header-section-number">1.5.1</span> CoAP POST</h3>
  314. <p>看看在IoT CoAP中的post示例。</p>
  315. <div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="kw">const</span> coap <span class="op">=</span> <span class="at">require</span>(<span class="st">&#39;coap&#39;</span>)
  316. <span class="op">,</span>request <span class="op">=</span> <span class="va">coap</span>.<span class="at">request</span>
  317. <span class="op">,</span>bl <span class="op">=</span> <span class="at">require</span>(<span class="st">&#39;bl&#39;</span>)
  318. <span class="op">,</span>req <span class="op">=</span> <span class="at">request</span>(<span class="op">{</span><span class="dt">hostname</span><span class="op">:</span> <span class="st">&#39;localhost&#39;</span><span class="op">,</span><span class="dt">port</span><span class="op">:</span><span class="dv">5683</span><span class="op">,</span><span class="dt">pathname</span><span class="op">:</span> <span class="st">&#39;&#39;</span><span class="op">,</span><span class="dt">method</span><span class="op">:</span> <span class="st">&#39;POST&#39;</span><span class="op">}</span>)<span class="op">;</span>
  319. <span class="va">req</span>.<span class="at">setOption</span>(<span class="st">&#39;Block2&#39;</span><span class="op">,</span> [<span class="kw">new</span> <span class="at">Buffer</span>(<span class="st">&#39;1&#39;</span>)<span class="op">,</span><span class="kw">new</span> <span class="at">Buffer</span>(<span class="st">&quot;&#39;must&#39;&quot;</span>)<span class="op">,</span> <span class="kw">new</span> <span class="at">Buffer</span>(<span class="st">&#39;23&#39;</span>)<span class="op">,</span> <span class="kw">new</span> <span class="at">Buffer</span>(<span class="st">&#39;12&#39;</span>)])<span class="op">;</span>
  320. <span class="va">req</span>.<span class="at">setHeader</span>(<span class="st">&quot;Accept&quot;</span><span class="op">,</span> <span class="st">&quot;application/json&quot;</span>)<span class="op">;</span>
  321. <span class="va">req</span>.<span class="at">on</span>(<span class="st">&#39;response&#39;</span><span class="op">,</span> <span class="kw">function</span>(res) <span class="op">{</span>
  322. <span class="va">res</span>.<span class="at">pipe</span>(<span class="at">bl</span>(<span class="kw">function</span>(err<span class="op">,</span> data) <span class="op">{</span>
  323. <span class="va">console</span>.<span class="at">log</span>(data)<span class="op">;</span>
  324. <span class="va">process</span>.<span class="at">exit</span>(<span class="dv">0</span>)<span class="op">;</span>
  325. <span class="op">}</span>))<span class="op">;</span>
  326. <span class="op">}</span>)<span class="op">;</span>
  327. <span class="va">req</span>.<span class="at">end</span>()<span class="op">;</span></code></pre></div>
  328. <p>Block2中一共有四个数据,相应的数据结果应该是</p>
  329. <div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="op">{</span> <span class="dt">name</span><span class="op">:</span> <span class="st">&#39;Block2&#39;</span><span class="op">,</span> <span class="dt">value</span><span class="op">:</span> <span class="op">&lt;</span>Buffer <span class="dv">31</span><span class="op">&gt;</span> <span class="op">}</span>
  330. <span class="op">{</span> <span class="dt">name</span><span class="op">:</span> <span class="st">&#39;Block2&#39;</span><span class="op">,</span> <span class="dt">value</span><span class="op">:</span> <span class="op">&lt;</span>Buffer <span class="dv">27</span> 6d <span class="dv">75</span> <span class="dv">73</span> <span class="dv">74</span> <span class="dv">27</span><span class="op">&gt;</span> <span class="op">}</span>
  331. <span class="op">{</span> <span class="dt">name</span><span class="op">:</span> <span class="st">&#39;Block2&#39;</span><span class="op">,</span> <span class="dt">value</span><span class="op">:</span> <span class="op">&lt;</span>Buffer <span class="dv">32</span> <span class="dv">33</span><span class="op">&gt;</span> <span class="op">}</span>
  332. <span class="op">{</span> <span class="dt">name</span><span class="op">:</span> <span class="st">&#39;Block2&#39;</span><span class="op">,</span> <span class="dt">value</span><span class="op">:</span> <span class="op">&lt;</span>Buffer <span class="dv">31</span> <span class="dv">32</span><span class="op">&gt;</span> <span class="op">}</span></code></pre></div>
  333. <p>这是没有解析的Block2,简单地可以用</p>
  334. <div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="va">_</span>.<span class="at">values</span>(e).<span class="at">toString</span>()</code></pre></div>
  335. <p>将结果转换为</p>
  336. <p>Block2,1 Block2,‘must’ Block2,23 Block2,12</p>
  337. <p>接着按“,”分开,</p>
  338. <div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="va">_</span>.<span class="at">values</span>(e).<span class="at">toString</span>().<span class="at">split</span>(<span class="st">&#39;,&#39;</span>)[<span class="dv">1</span>]</code></pre></div>
  339. <p>就有</p>
  340. <div class="sourceCode"><pre class="sourceCode bash"><code class="sourceCode bash"><span class="kw">[</span> <span class="st">&#39;1&#39;</span>, <span class="st">&#39;\&#39;</span>must<span class="dt">\&#39;</span><span class="st">&#39;, &#39;</span>23<span class="st">&#39;, &#39;</span>12<span class="st">&#39; ]</span></code></pre></div>
  341. <p>便可以很愉快地将其post到数据库中了,</p>
  342. <p>在做IoT-CoAP的过程中只支持JSON,查阅CoAP的草稿时发现支持了诸多的Content Types。</p>
  343. <h3 id="coap-content-types"><span class="header-section-number">1.5.2</span> CoAP Content Types</h3>
  344. <p>以下文字来自谷歌翻译:</p>
  345. <blockquote>
  346. <p>互联网媒体类型是通过HTTP字符串标识,如“application/xml”。该字符串是由一个顶层的类型“applicaion”和子类型的“XML”。为了尽量减少使用这些类型的媒体类型来表示的开销消息有效载荷,COAP定义一个标识符编码方案互联网媒体类型的子集。预计这桌将可扩展标识符的值的IANA维护。内容类型选项被格式化为一个8位无符号整数。初始映射到一个合适的互联网媒体类型标识符表所示。复合型高层次类型(multipart和不支持消息)。标识符值是从201-255保留的特定于供应商的,应用程序特定的或实验使用和不由IANA。</p>
  347. </blockquote>
  348. <p>下面是HTTP的标识符及类型</p>
  349. <table>
  350. <thead>
  351. <tr class="header">
  352. <th align="left">Internet media type</th>
  353. <th align="left">Identifier</th>
  354. </tr>
  355. </thead>
  356. <tbody>
  357. <tr class="odd">
  358. <td align="left">text/plain (UTF-8)</td>
  359. <td align="left">0</td>
  360. </tr>
  361. <tr class="even">
  362. <td align="left">text/xml (UTF-8)</td>
  363. <td align="left">1</td>
  364. </tr>
  365. <tr class="odd">
  366. <td align="left">text/csv (UTF-8)</td>
  367. <td align="left">2</td>
  368. </tr>
  369. <tr class="even">
  370. <td align="left">text/html (UTF-8)</td>
  371. <td align="left">3</td>
  372. </tr>
  373. <tr class="odd">
  374. <td align="left">image/gif</td>
  375. <td align="left">21</td>
  376. </tr>
  377. <tr class="even">
  378. <td align="left">image/jpeg</td>
  379. <td align="left">22</td>
  380. </tr>
  381. <tr class="odd">
  382. <td align="left">image/png</td>
  383. <td align="left">23</td>
  384. </tr>
  385. <tr class="even">
  386. <td align="left">image/tiff</td>
  387. <td align="left">24</td>
  388. </tr>
  389. <tr class="odd">
  390. <td align="left">audio/raw</td>
  391. <td align="left">25</td>
  392. </tr>
  393. <tr class="even">
  394. <td align="left">video/raw</td>
  395. <td align="left">26</td>
  396. </tr>
  397. <tr class="odd">
  398. <td align="left">application/link-format [I-D.ietf-core-link-format]</td>
  399. <td align="left">40</td>
  400. </tr>
  401. <tr class="even">
  402. <td align="left">application/xml</td>
  403. <td align="left">41</td>
  404. </tr>
  405. <tr class="odd">
  406. <td align="left">application/octet-stream</td>
  407. <td align="left">42</td>
  408. </tr>
  409. <tr class="even">
  410. <td align="left">application/rdf+xml</td>
  411. <td align="left">43</td>
  412. </tr>
  413. <tr class="odd">
  414. <td align="left">application/soap+xml</td>
  415. <td align="left">44</td>
  416. </tr>
  417. <tr class="even">
  418. <td align="left">application/atom+xml</td>
  419. <td align="left">45</td>
  420. </tr>
  421. <tr class="odd">
  422. <td align="left">application/xmpp+xml</td>
  423. <td align="left">46</td>
  424. </tr>
  425. <tr class="even">
  426. <td align="left">application/exi</td>
  427. <td align="left">47</td>
  428. </tr>
  429. <tr class="odd">
  430. <td align="left">application/x-bxml</td>
  431. <td align="left">48</td>
  432. </tr>
  433. <tr class="even">
  434. <td align="left">application/fastinfoset</td>
  435. <td align="left">49</td>
  436. </tr>
  437. <tr class="odd">
  438. <td align="left">application/soap+fastinfoset</td>
  439. <td align="left">50</td>
  440. </tr>
  441. <tr class="even">
  442. <td align="left">application/json</td>
  443. <td align="left">51</td>
  444. </tr>
  445. </tbody>
  446. </table>
  447. <p>而在CoAP中只有简单地几个</p>
  448. <table>
  449. <thead>
  450. <tr class="header">
  451. <th align="left">Media type</th>
  452. <th align="left">Encoding</th>
  453. <th align="left">Id.</th>
  454. <th align="left">Reference</th>
  455. </tr>
  456. </thead>
  457. <tbody>
  458. <tr class="odd">
  459. <td align="left">text/plain;</td>
  460. <td align="left">-</td>
  461. <td align="left">0</td>
  462. <td align="left">[RFC2046][RFC3676][RFC5147]</td>
  463. </tr>
  464. <tr class="even">
  465. <td align="left">charset=utf-8</td>
  466. <td align="left"></td>
  467. <td align="left"></td>
  468. <td align="left"></td>
  469. </tr>
  470. <tr class="odd">
  471. <td align="left">application/</td>
  472. <td align="left">-</td>
  473. <td align="left">40</td>
  474. <td align="left">[RFC6690]</td>
  475. </tr>
  476. <tr class="even">
  477. <td align="left">link-format</td>
  478. <td align="left"></td>
  479. <td align="left"></td>
  480. <td align="left"></td>
  481. </tr>
  482. <tr class="odd">
  483. <td align="left">application/xml</td>
  484. <td align="left">-</td>
  485. <td align="left">41</td>
  486. <td align="left">[RFC3023]</td>
  487. </tr>
  488. <tr class="even">
  489. <td align="left">application/</td>
  490. <td align="left">-</td>
  491. <td align="left">42</td>
  492. <td align="left">[RFC2045][RFC2046]</td>
  493. </tr>
  494. <tr class="odd">
  495. <td align="left">octet-stream</td>
  496. <td align="left"></td>
  497. <td align="left"></td>
  498. <td align="left"></td>
  499. </tr>
  500. <tr class="even">
  501. <td align="left">application/exi</td>
  502. <td align="left">-</td>
  503. <td align="left">47</td>
  504. <td align="left">[EXIMIME]</td>
  505. </tr>
  506. <tr class="odd">
  507. <td align="left">application/json</td>
  508. <td align="left">-</td>
  509. <td align="left">50</td>
  510. <td align="left">[RFC4627]</td>
  511. </tr>
  512. </tbody>
  513. </table>
  514. <p>简单地说就是:</p>
  515. <p><code>诸如application/json的Content Types在CoAP中应该是50</code>。如上表所示的结果是其对应的结果,这样的话可以减少传递的信息量。</p>
  516. <h2 id="coap-json"><span class="header-section-number">1.6</span> CoAP JSON</h2>
  517. <p>于是在一开始的时候首先支持的便是“application/json”这样的类型。</p>
  518. <p>首先判断请求的header</p>
  519. <div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="va">request_helper</span>.<span class="at">getHandler</span> <span class="op">=</span> <span class="kw">function</span>(req<span class="op">,</span> res) <span class="op">{</span>
  520. <span class="cf">switch</span> (<span class="va">req</span>.<span class="at">headers</span>[<span class="st">&#39;Accept&#39;</span>]) <span class="op">{</span>
  521. <span class="cf">case</span> <span class="st">&quot;application/json&quot;</span><span class="op">:</span>
  522. <span class="va">qh</span>.<span class="at">returnJSON</span>(req<span class="op">,</span> res)<span class="op">;</span>
  523. <span class="cf">break</span><span class="op">;</span>
  524. <span class="cf">case</span> <span class="st">&quot;application/xml&quot;</span><span class="op">:</span>
  525. <span class="va">qh</span>.<span class="at">returnXML</span>(req<span class="op">,</span> res)<span class="op">;</span>
  526. <span class="cf">break</span><span class="op">;</span>
  527. <span class="op">}</span>
  528. <span class="op">};</span></code></pre></div>
  529. <p>再转至相应的函数处理,而判断的依据则是Accept是不是“application/json”。</p>
  530. <div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="at">registerFormat</span>(<span class="st">&#39;text/plain&#39;</span><span class="op">,</span> <span class="dv">0</span>)
  531. <span class="at">registerFormat</span>(<span class="st">&#39;application/link-format&#39;</span><span class="op">,</span> <span class="dv">40</span>)
  532. <span class="at">registerFormat</span>(<span class="st">&#39;application/xml&#39;</span><span class="op">,</span> <span class="dv">41</span>)
  533. <span class="at">registerFormat</span>(<span class="st">&#39;application/octet-stream&#39;</span><span class="op">,</span> <span class="dv">42</span>)
  534. <span class="at">registerFormat</span>(<span class="st">&#39;application/exi&#39;</span><span class="op">,</span> <span class="dv">47</span>)
  535. <span class="at">registerFormat</span>(<span class="st">&#39;application/json&#39;</span><span class="op">,</span> <span class="dv">50</span>)</code></pre></div>
  536. <p>对应地我们需要在一发出请求的时候设置好Accept,要不就没有办法返回我们需要的结果。</p>
  537. <div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="va">req</span>.<span class="at">setHeader</span>(<span class="st">&quot;Accept&quot;</span><span class="op">,</span> <span class="st">&quot;application/json&quot;</span>)<span class="op">;</span></code></pre></div>
  538. <p><strong>返回JSON</strong></p>
  539. <p>在给IoT CoAP添加了JSON支持之后,变得非常有意思,至少我们可以获得我们想要的结果。在上一篇中我们介绍了一些常用的工具——<a href="http://www.phodal.com/blog/coap-command-line-tools-set/">CoAP 命令行工具集</a>。</p>
  540. <p><strong>CoAP客户端代码</strong></p>
  541. <p>开始之前我们需要有一个客户端代码,以便我们的服务端可以返回正确的数据并解析</p>
  542. <div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="kw">var</span> coap <span class="op">=</span> <span class="at">require</span>(<span class="st">&#39;coap&#39;</span>)<span class="op">;</span>
  543. <span class="kw">var</span> requestURI <span class="op">=</span> <span class="st">&#39;coap://localhost/&#39;</span><span class="op">;</span>
  544. <span class="kw">var</span> url <span class="op">=</span> <span class="at">require</span>(<span class="st">&#39;url&#39;</span>).<span class="at">parse</span>(requestURI <span class="op">+</span> <span class="st">&#39;id/1/&#39;</span>)<span class="op">;</span>
  545. <span class="va">console</span>.<span class="at">log</span>(<span class="st">&quot;Request URL: &quot;</span> <span class="op">+</span> <span class="va">url</span>.<span class="at">href</span>)<span class="op">;</span>
  546. <span class="kw">var</span> req <span class="op">=</span> <span class="va">coap</span>.<span class="at">request</span>(url)<span class="op">;</span>
  547. <span class="kw">var</span> bl <span class="op">=</span> <span class="at">require</span>(<span class="st">&#39;bl&#39;</span>)<span class="op">;</span>
  548. <span class="va">req</span>.<span class="at">setHeader</span>(<span class="st">&quot;Accept&quot;</span><span class="op">,</span> <span class="st">&quot;application/json&quot;</span>)<span class="op">;</span>
  549. <span class="va">req</span>.<span class="at">on</span>(<span class="st">&#39;response&#39;</span><span class="op">,</span> <span class="kw">function</span>(res) <span class="op">{</span>
  550. <span class="va">res</span>.<span class="at">pipe</span>(<span class="at">bl</span>(<span class="kw">function</span>(err<span class="op">,</span> data) <span class="op">{</span>
  551. <span class="kw">var</span> json <span class="op">=</span> <span class="va">JSON</span>.<span class="at">parse</span>(data)<span class="op">;</span>
  552. <span class="va">console</span>.<span class="at">log</span>(json)<span class="op">;</span>
  553. <span class="op">}</span>))<span class="op">;</span>
  554. <span class="op">}</span>)<span class="op">;</span>
  555. <span class="va">req</span>.<span class="at">end</span>()<span class="op">;</span></code></pre></div>
  556. <p>代码有点长内容也有点多,但是核心是这句话:</p>
  557. <div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="va">req</span>.<span class="at">setHeader</span>(<span class="st">&quot;Accept&quot;</span><span class="op">,</span> <span class="st">&quot;application/json&quot;</span>)<span class="op">;</span></code></pre></div>
  558. <p>这样的话,我们只需要在我们的服务端一判断,</p>
  559. <div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="cf">if</span>(<span class="va">req</span>.<span class="at">headers</span>[<span class="st">&#39;Accept&#39;</span>] <span class="op">==</span> <span class="st">&#39;application/json&#39;</span>) <span class="op">{</span>
  560. <span class="co">//do something</span>
  561. <span class="op">};</span></code></pre></div>
  562. <p>这样就可以返回数据了</p>
  563. <p><strong>CoAP Server端代码</strong></p>
  564. <p>Server端的代码比较简单,判断一下</p>
  565. <div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="cf">if</span> (<span class="va">req</span>.<span class="at">headers</span>[<span class="st">&#39;Accept&#39;</span>] <span class="op">==</span> <span class="st">&#39;application/json&#39;</span>) <span class="op">{</span>
  566. <span class="at">parse_url</span>(<span class="va">req</span>.<span class="at">url</span><span class="op">,</span> <span class="kw">function</span>(result)<span class="op">{</span>
  567. <span class="va">res</span>.<span class="at">end</span>(result)<span class="op">;</span>
  568. <span class="op">}</span>)<span class="op">;</span>
  569. <span class="va">res</span>.<span class="at">code</span> <span class="op">=</span> <span class="st">&#39;2.05&#39;</span><span class="op">;</span>
  570. <span class="op">}</span></code></pre></div>
  571. <p>请求的是否是JSON格式,再返回一个205,也就是Content,只是这时设计是请求一个URL返回对应的数据。如</p>
  572. <div class="sourceCode"><pre class="sourceCode bash"><code class="sourceCode bash"><span class="kw">coap</span>://localhost/id/1/</code></pre></div>
  573. <p>这时应该请求的是ID为1的数据,即</p>
  574. <div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript">[ <span class="op">{</span> <span class="dt">id</span><span class="op">:</span> <span class="dv">1</span><span class="op">,</span> <span class="dt">value</span><span class="op">:</span> <span class="st">&#39;is id 1&#39;</span><span class="op">,</span> <span class="dt">sensors1</span><span class="op">:</span> <span class="dv">19</span><span class="op">,</span> <span class="dt">sensors2</span><span class="op">:</span> <span class="dv">20</span> <span class="op">}</span>]</code></pre></div>
  575. <p>而parse_url只是从数据库从读取相应的数据。</p>
  576. <div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="kw">function</span> <span class="at">parse_url</span>(url <span class="op">,</span>callback) <span class="op">{</span>
  577. <span class="kw">var</span> db <span class="op">=</span> <span class="kw">new</span> <span class="va">sqlite3</span>.<span class="at">Database</span>(config[<span class="st">&quot;db_name&quot;</span>])<span class="op">;</span>
  578. <span class="kw">var</span> result <span class="op">=</span> []<span class="op">;</span>
  579. <span class="va">db</span>.<span class="at">all</span>(<span class="st">&quot;SELECT * FROM basic;&quot;</span><span class="op">,</span> <span class="kw">function</span>(err<span class="op">,</span> rows) <span class="op">{</span>
  580. <span class="at">callback</span>(<span class="va">JSON</span>.<span class="at">stringify</span>(rows))<span class="op">;</span>
  581. <span class="op">}</span>)
  582. <span class="op">}</span></code></pre></div>
  583. <p>并且全部都显示出来,设计得真是有点不行,不过现在已经差不多了。</p>
  584. </body>
  585. </html>