数据通信

Table of Contentsgenerated with DocToc

数据通信

HTTP

HTTP 为一个通信协议。HTTP 客户端发起请求并创建端口。HTTP 服务器在端口监听客户端的请求。HTTP 服务器在收到请求后则返回状态和所请求的内容。

网页浏览全过程 (粗浅流程)

  • 域名解析
    • 搜索浏览器自身 DNS 缓存
    • 搜索操作系统自身 DNS 缓存(如上一级未找到或已失效)
    • 读取本地 HOST 文件 (如上一级未找到或已失效,/etc/hosts
    • 浏览器发起 DNS 系统调用请求
      • ISP 服务器查找自身缓存
      • ISP 服务器发起迭代(逐域寻找需要的地址)请求
  • 得到请求资源的 IP 地址
  • 发起 HTTP “三次握手”(下面为一个超级简化版)
    • 建立连接,等待服务器确认
    • 服务器接受请求,回复客户
    • 客户端与服务器连接成功(TCP/IP 连接成功)
  • 客户根据协议发送请求
  • 服务器更具请求返回客户需求资源
  • 客户获得资源

HTTP 事务

数据通信 - 图1

HTTP 请求报文

数据通信 - 图2

其中包括主机地址,HTTP 协议版本号。头部由键值对组成。因为此请求为 GET 方法所以请求体为空。

HTTP 回复报文

数据通信 - 图3

其中包括 HTTP 版本号,状态码及状态码描述。头部依然为键值对组成。主体则为 HTML 文件。

常用 HTTP 方法

常用方法

方法描述是否包含主题
GET从服务器获取一份文档
POST向服务器发送需要处理的数据
PUT将请求的主题部分储存在服务器上
DELETE从服务器删除一份文档

不常用方法

方法描述是否包含主题
HEAD只从服务器获取头文档的首部
TRACE对可能经过代理服务器传送到服务器上的报文进行追踪
OPTIONS决定可以在服务器上执行的方法

URL 构成

  1. http://www.github.com:8080/index.html?user=li-xinyang&lang=zh-CN#home
  2. | | | | | |
  3. protocol | | | | |
  4. hostname port | | |
  5. \ / pathname search hash
  6. host

可选部分包括

  • port
  • pathname
  • search
  • hashNOTE:上面提供的 URL 地址仅为参考所用。

HTTP 版本

  • HTTP/0.9 1991年 HTTP 原型,存在设计缺陷
  • HTTP/1.0 第一个广泛应用版本
  • HTTP/1.0+ 添加持久的 keep-alive 链接,虚拟主机支持,代理连接支持,成为非官方的事实版本
  • HTTP/1.1 校正结构性缺陷,明确语义,引入重要的新能优化措施,删除不好的特性(当前使用版本)NOTE:此文写于2015年6月。

常见 HTTP 状态码

状态码描述代码描述
200请求成功,一般用于 GET 和 POST 方法OK
301资源移动。所请求资源自动到新的 URL,浏览器自动跳转至新的 URLMoved Permanently
304未修改。所请求资源未修改,浏览器读取缓存数据Not Modified
400请求语法错误,服务器无法解析Bad Request
404未找到资源,可以设置个性“404页面”Not Found
500服务器内部错误Internal Server Error

数据通信 - 图4

AJAX

AJAX(Asynchronous JavaScript and HTML)异步获取数据的概念,由 Jesse James Garrett 在2005年提出。

AJAX 请求全过程

数据通信 - 图5

AJAX 调用

三部完成 AJAX 调用

  • 创建 XHR 对象
  • 处理返回数据及错误处理
  • 发送请求
  1. var xhr = new XMLHttpRequest();
  2. xhr.onreadystatechange = function(callback) {
  3. if (xhr.readyState === 4) {
  4. if ((xhr.status >== 200 && xhr.status < 300) || xhr.status === 304) {
  5. callback(xhr.responseText);
  6. } else {
  7. console.error('Request was unsuccessful: ' + xhr.status);
  8. }
  9. }
  10. }
  11. xhr.open('get', 'exmaple.json', true);
  12. xhr.setRequestHeader('myHeader', 'myValue');
  13. xhr.send(null);

NOTE:xhr.onload 只针对当 readyState === 4status === 200 时的事件。

open
  1. xhr.open(method, url[, async = true]);
  • method 为上面说过的 HTTP 方法(例如,GET、POST)
  • url 为资源地址
  • async 默认为真,用于设置异步请求
setRequestHeader
  1. xhr.setRequestHeader('myHeader', 'myValue');
  2. xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');

用于设置头部的键值对。

send
  1. xhr.send([data=null]);
  2. xhr.send()

数据可包含字符串或表单数控,但需要提前为 RequestHeader 做设置。

请求参数序列化

将查询参数使用字符串,跟入资源地址中。

  1. xhr.open('get', 'example.json?' + 'name=value&age=value', true);

对象转换字符串的函数实现

  1. function serialize(data) {
  2. if (!data) return '';
  3. var pairs = [];
  4. for (var name in data) {
  5. if (!data.hasOwnProperty(name)) continue;
  6. if (typeof data[name] === 'function') continue;
  7. var value = data[name].toString();
  8. name = encodeURIComponent(name);
  9. value = encodeURIComponent(value);
  10. pairs.push(name + '=' + value);
  11. }
  12. return pairs.join('&');
  13. }

GET 请求

  1. var url = 'example.json?' + serialize(formData);
  2. xhr.open('get', url, true);
  3. xhr.send(null);

POST 请求

查询参数需要作为 send() 的存数传入。

  1. xhr.open('get', 'example.json', true);
  2. xhr.send(serialize(formData));

同源策略

两个页面拥有相同的协议(Protocol)、端口(Port)、和主机(host)那么这两个页面就是属于同一个源(Origin)。

  1. http://www.github.com:8080/index.html?user=li-xinyang&lang=zh-CN#home
  2. | | | | | |
  3. protocol | | | | |
  4. hostname port | | |
  5. \ / pathname search hash
  6. host
  7. |-----完全一致则同源------|

跨域资源访问

不满足同源策略的资源访问均属于跨域资源访问,W3C 定义了 CORS。现代浏览器已经实现了 CORS 的支持。

CORS 原理实现图

数据通信 - 图6

其他跨域技术
  • Frame 代理
  • JSONP
  • Comet
  • Web Sockets
  • Frame 代理

关于 Frame 代理的更多内容在这里

数据通信 - 图7

优点:

  • 参照 CORS 标准
  • 支持各种请求方法 GET POST PUT DELETE缺点:

  • 需要在目标服务器防止代理文件(造成延时)

  • 低版本在大并发消息通信机制会产生延时JSONP

全程为 JSON with Padding(填充式 JSON),它利用 <script> 可以跨域的原理。请求一段 JavaScript 代码,然后执行 JavaScript 代码来实现跨域。

  1. function handleResponse(response) {
  2. alert(response.name);
  3. }
  4. var script = document.createElement('script');
  5. script.src = 'http://localhost:3000/json?callback=handleResponse';
  6. document.body.insertBefore(script, document.body.firstChild);