Table of Contents generated with DocToc

数据通信

HTTP

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

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

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

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
  • hash

NOTE:上面提供的 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,浏览器自动跳转至新的 URL Moved 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 调用

  1. 创建 XHR 对象
  2. 处理返回数据及错误处理
  3. 发送请求
  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);