App网络基础知识概括

jxmu3532 3年前
   <h2><strong>前言</strong></h2>    <p>网络模块是 App 应用最基础最核心的模块, 稳定高效的网络处理是良好用户体验的基本保障。 本文介绍日常开发中常用的网络协议以及使用方法。</p>    <h2><strong>目录</strong></h2>    <ul>     <li>http 协议</li>     <li>http 的问题以及优化策略</li>     <li>安全处理策略</li>     <li>WebSocket 协议解析</li>     <li>Http2 协议简介</li>    </ul>    <h2><strong>Http 协议</strong></h2>    <p>先看一下网络请求传输的过程:</p>    <p><img src="https://simg.open-open.com/show/2c861425d3ffc30a19c0a7e2ffd34d4c.png"></p>    <p>核心步骤主要是以下几步:</p>    <ol>     <li>DNS 解析, 获取服务器的 ip 地址列表</li>     <li>TCP/IP 链接到服务器</li>     <li>在 TCP/IP 上构建协议规则</li>     <li>服务器收到请求,通过通道返回响应</li>     <li>Client 收到响应后关闭通道</li>    </ol>    <p>Http 协议分为 Request, Response 两部分。 客户端发起一个 Request; 服务器处理后,返回一个 Response。</p>    <h3><strong>Request</strong></h3>    <p>看一下 Request 的构成:</p>    <p><img src="https://simg.open-open.com/show/b09d5b505f8a8d5bf8386157203e6a4a.png"></p>    <p>上半部分为请求头, 下半部分为请求体。</p>    <p>第一行描述请求的方式,请求的路径, http 的协议版本。 之后每一行描述一个请求头字段。 请求头和请求体之间以两个换行分割。</p>    <p>常用的请求头字段:</p>    <ul>     <li>Content-Type: 表示请求内容的类型。 一般 api 请求主要使用 <p>application/json</p> <p>application/x-www-form-urlencoded</p> <p>multipart/form-data</p> </li>     <li>Content-Length: 请求体大小。 服务器根据这个值才能获取完整的请求数据</li>     <li>User-Agent: 客户端可以随意设置的一个值, 用来描述客户端的信息</li>     <li>Connection: 链接类型。 上图中 Keep-Alive 表示服务器收到请求号保持链接不要关闭。</li>     <li>Accept-Encoding: gzip 表示当前客户端接受 gzip 编码的响应内容</li>    </ul>    <h3><strong>Response</strong></h3>    <p><img src="https://simg.open-open.com/show/339a5af170bc2eaff3c8c3efcf76156f.png"></p>    <p>Response 同样分为<strong>头</strong>和<strong>体</strong>两部分。</p>    <p>响应码: 请求是否成功根据响应码判断。 每种响应码都对应各自的含义。详细参考 <a href="/misc/goto?guid=4959716203388992136" rel="nofollow,noindex">wiki</a></p>    <p>常用的响应头:</p>    <ul>     <li> <p>Connection: keep-alive. 表示响应未关闭, 客户端实现上同样需要保持链接未关闭</p> </li>     <li> <p>Cache-Control: 协议的缓存策略</p> </li>     <li> <p>Content-Encoding: gzip 表示当前返回的内容采用的 gzip 编码。 解析数据时使用 gzip 解码</p> </li>     <li> <p>Content-Type:返回数据的内容格式</p> </li>    </ul>    <h3><strong>Cookie</strong></h3>    <p>cookie 是随着 Response 返回的键值对数据, 保存在本地。 下次再访问同一个域时, 将 Cookie 的 kvs 随着 Request 带到 Server。 后台开发人员可以根据业务的需求设置对应的 Cookie。</p>    <h2><strong>Http 的问题</strong></h2>    <p>对于 App 的场景来说, 使用 http 协议处理网络请求是一种最简单, 但不是最高效的方式(个人观点)</p>    <ol>     <li>最大的问题, 延迟。 App 的请求都很分散, 大部分发起的请求都需要重新构建整个链接, 延迟问题很严重。</li>     <li>无效数据重复提交。 每次请求都会将同样的 headers 提交到服务器。</li>     <li>单向数据通道。 服务器属于被动响应模式, 无法做到主动推送数据。</li>    </ol>    <h2><strong>Http 优化策略</strong></h2>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/fdd6330ffb421acb8a590d12d4de4a27.png"></p>    <p style="text-align: center;">Http耗时</p>    <p>如上图, Http 请求的耗时主要由四部分组成。 围绕这四部分分析优化策略。</p>    <h3><strong>1. Cache</strong></h3>    <p>最快的请求是不发起请求。不仅在协议层处理网络的缓存, 还需要在业务层处理数据的缓存。 在不必要的情况下, 尽量不发起网络请求, 直接使用缓存中的数据。</p>    <h3><strong>2. DNS</strong></h3>    <p>系统都有 Dns 解析的实现。 默认情况下直接调用系统 API 执行 Dns 查询操作。</p>    <ul>     <li> <p>Dns 优化策略一</p> <p>实现 Dns 二级缓存。 当执行请求时,需要调用 Dns 查询。 将 ips 结果缓存起来, 下次再请求同样的域名时,直接从缓存内取出结果, 而不需要再次调用系统查询</p> </li>    </ul>    <h3><strong>3. 链接复用</strong></h3>    <p>http 1.1 默认是设置 Connection:Keep-Alive。 就是表示请求完成后并不马上关闭, 后续相同的请求通过链路的复用, 节省 tcp 链接建立的耗时。</p>    <h3><strong>4. 请求</strong></h3>    <p>在带宽固定的情况下, 减少提交的数据包大小, 降低数据传输的耗时。</p>    <ul>     <li>策略一<br> 选择合理的数据提交方式。 一般常用的 post 数据提交格式有</li>     <li>JSON Content-Type: application/json</li>     <li>UrlEncode Content-Type:application/x-www-form-urlencoded</li>     <li>formdata Content-Type:application/form-data</li>    </ul>    <p>相对来说 json 和 urlEncode 的格式占用比较小。 formdata 比较大, 一般是上传文件时使用。</p>    <ul>     <li> <p>策略二</p> <p>对提交的内容进行压缩。 同时设置 Content-Encoding。</p> </li>    </ul>    <h3><strong>5. 响应</strong></h3>    <p>原理同上, 减小数据包的大小, 降低数据传输的耗时。</p>    <ul>     <li>策略一<br> 服务器返回数据时将数据做压缩处理。</li>     <li>策略二<br> 使用 webp 格式的图片资源。 app 的流量消耗的大头在于图片, 使用 webp 格式的图片能够减少 40%+ 的流量消耗。</li>    </ul>    <h2><strong>安全</strong></h2>    <p>安全处理策略有两个方面。 一种是在使用上增加安全校验, 一种是在协议上使用安全协议,如 Https。</p>    <h3><strong>请求防篡改</strong></h3>    <p>前后端交互常规做法的一种。 对请求的参数的某些值连在一块, 再通过加盐算 MD5 值生成一个签名。 将签名值附加到请求参数中。 后端收到请求后同样需要验证这个签名, 不一致的话说明请求参数已经被篡改了, 不予通过。</p>    <p>signature = md5(value1+value2+value3+solt);</p>    <p>稍微更严格一点的方式是,对所有请求参数根据 key 值做自然排序, 再用上述方法算一遍签名。</p>    <p>这种方式主要是为了防止参数被篡改, 并不能防止被拦截。</p>    <h3><strong>Https</strong></h3>    <p>使用 Https 能从协议上解决安全问题。全面升级到 Https 是目前业界的趋势。 下图是 Https 的处理过程简图:</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/5540e554b4fd37d5329bd47a4a15c2d3.png"></p>    <h2><strong>WebSocket 协议</strong></h2>    <p>Http 协议是一种被动式的处理消息的方式。 app 很多场景下需要由服务器主动将数据推送到客户端。 使用 WS 协议维持客户端到服务器的长连接是一种很好的解决方案。 目前在 IM 或直播的场景下应用b</p>    <p>比较广泛。</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/61e409596847a741f8dac74edd08e78b.png"></p>    <p style="text-align: center;">WS 请求</p>    <p style="text-align: center;"><img src="https://simg.open-open.com/show/13d2377ec8825752f4a0665cff1e0642.png"></p>    <p style="text-align: center;">WS 响应</p>    <p>上面两张图为 ws 协议请求和响应。</p>    <ol>     <li>客户端发起一个 http 的 get 请求。</li>     <li>请求头中表示链接方式为升级(Connection: Upgrade) 到 websocket协议(Upgrade: websocket)</li>     <li>Sec-WebSocket-Key: 为客户端生成的随机字符串(掩码值)</li>     <li>Sec-WebSocket-Version: 13 表示使用 ws 1.3 版本。</li>     <li>响应码 101 表示协议切换成功, 协议升级到 websocket (Upgrade:websocket)</li>    </ol>    <p>在看一下 ws 协议下的每帧数据组成:</p>    <p><img src="https://simg.open-open.com/show/679184897d1f4938cd64524ac593bb3d.png"></p>    <p>每帧数据都包含 2byte 的头信息。</p>    <p>FIN 表示是否为最后一帧</p>    <p>RSV1/2/3 为扩展字段。客户端与服务器可以通过约定这几个字段的值实现协议上的附加操作, 比如是否开启数据压缩。</p>    <p>OP Code 为每一帧的操作类型。 比如当前帧是操作帧还是数据帧</p>    <p>MASK 0/1 表示是否设置了掩码</p>    <p>LENGTH 为数据包长度</p>    <p>在 2byte 头信息之后带上整个帧的真实数据。</p>    <h2><strong>Http2 协议</strong></h2>    <p>下一代 http 协议。 解决了诸多 http 下的问题, 被越来越广泛的应用。 </p>    <h2><strong>App 下的理想网络模型特点</strong></h2>    <p>App 的网络场景要比 pc 上复杂很多, 也不稳定的多。 对于 app 来说, 理想的网络模型特点应该要有:</p>    <ul>     <li> <p>低延时</p> </li>     <li> <p>安全</p> </li>     <li> <p>双向数据通道</p> </li>    </ul>    <p>在不同的场景下使用不同的工具去解决问题, 重点是要熟悉每种协议的特点,以及如何使用。</p>    <p> </p>    <p> </p>    <p>来自:http://www.jianshu.com/p/b657a1bb0c32</p>    <p> </p>