ajax 交互模型(xhr代码)、git/post 对比、tcp 协议

传统的<from>交互方式:

<!-- get -->
<form action="/get">
  用户名:<input type="text" name="user"/>
  密码:<input type="password" name="password"/>
  <input type="submit" value="提交"/>
<form>
 
<!-- post -->
<form action="/post" method="POST" enctype="application/x-www-form-urlencoded" >
  用户名:<input type="text" name="user"/>
  密 码:<input type="password" name="password" />
  <input type="submit" value="提交">
</form>

原生的 ajax 交互模型

ajax 的模型叫 电话模式

  1. 先有一个电话 创建ajax对象
  2. 输入号码(拨号) 填写请求地址 xhr.open("请求的方式","url地址"+具体字段,请求异步默认为true)
  3. 发送 send()
  4. 等待 xhr.onload
  5. 成功接收 在xhr.onload中接收到数据 xhr.responseText
// 创建一个XHR对象{AJAX实例对象}
let xhr = new XMLHttpRequest;

// 打开一个URL地址{发送请求之前的配置信息}
// xhr.open(请求方式, 请求API地址, false同步/true异步{默认}, 用户名, 密码)
xhr.open('GET', './data.json');

// 设置其余的配置信息:请求头信息 & 超时 & 跨域资源共享 ...{必须在OPEN之后}
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); // 请求头信息的内容不能是中文或者一些特殊符号
xhr.timeout = 60000; // 设置超时时间  0就是不设置
xhr.withCredentials = true; // 在跨域资源共享中,是否允许携带资源凭证「例如:cookie」,默认false

// 监听XHR状态 & HTTP状态码
xhr.onreadystatechange = () => {
  let {
    status,
    statusText,
    readyState
  } = xhr;
  // 基于HTTP状态码验证是否请求成功「以2/3开始的都是成功」
  if (status >= 200 && status < 400) {
    if (readyState === 2) {
      // 响应头信息已经拿到  
      //   + xhr.getResponseHeader([key]) 获取指定响应头信息
      //   + xhr.getAllResponseHeaders() 获取所有响应头信息「字符串」
      let serverTime = xhr.getResponseHeader('date'); //GMT 格林尼治时间
      serverTime = new Date(serverTime); //把格林尼治时间变为北京时间
      console.log('服务器时间:', serverTime);
    }
    if (readyState === 4) {
      // 响应主体信息已经拿到
      //   + xhr.response 响应主体信息「服务器返回啥格式就是啥格式」
      //   + xhr.responseText 以字符串格式获取
      //   + xhr.responseXML 以XML格式获取
      //   + xhr.responseType 存储服务器返回数据的格式  空字符串{默认}、“arraybuffer”、“blob”“document”、“json”、“text” 这些格式就是服务器支持的返回给客户端的数据格式
      let result = xhr.responseText; // 由于服务器一般返回给客户端的都是JSON格式字符串,所以我们一般都于responseText获取响应主体信息
      result = JSON.parse(result);
      console.log('响应主体信息:', result);
    }
    return;
  }
  // 获取数据失败:提示 && 移除监听
  console.log(`很遗憾,当前请求失败,请稍后再试!`, status, statusText);
  xhr.onreadystatechange = null;
};

// 发送AJAX请求
// 请求主体信息支持的格式:字符串「urlencoded、json、普通字符串...」、arrayBuffer、blob、FormData
xhr.send();
// POST通过send传参:xhr.send({name: 'hanlu', sex: 0, age: 32});

// xhr.abort(); // 强制中断ajax请求,如果超时会自动中断。

// 等待服务器响应
xhr.onload = function(){
  // xhr.getAllResponseHeaders() // 获取所有的响应头信息
  // xhr.getResponseHeader([key]) // 获取响应头中的某个属性名对应的属性值
  // 接收到数据,并开始处理
  let data = JSON.parse(xhr.responseText);
  console.log(data);
};

jQuery 的 ajax 的方式:

首先要引入 jQuery 文件

$.ajax({
  url: 'www.baidu.com', // 必须传,(向后台要)
  dataType: 'json',
  data: {
    user: '刘德华'
    password: 'xxx'
    // key(为前后端一起定义的字段):val(前端传的数据)
  },
  success: function (json\data) {
    let data = JSON.parse(json);// 如果拿到的数据是json就转成对象,如果是data(对象)就直接使用

    // 判断状态并处理数据
    if(data.code === 0){
      $("#txt").removeClass("ok");
      $("#txt").addClass("error");
    };
    if(data.code === 1){
      $("#txt").removeClass("error");
      $("#txt").addClass("ok");
    };
  }
});

XHR状态值:

XMLHttpRequest在低版本IE下(除IE6),里面的事件和属性都有不同。比如 xhr.onload = function( ){ } 事件只有高版本才能使用。
但是所有版本都支持:xhr.onreadystatechange = function( ){ } 能够监听到请求的步骤。
onreadystatechange 能够监听到五步,每步都有对应的数字0-4,但是第0步监听不到,最多只能监听1-4,通过xhr.readyState拿到这些数

  • UNSENT: 0 初始化实例
  • OPENED: 1 执行了OPEN方法【服务器连接已建立】
  • HEADERS_RECEIVED: 2 响应头信息已经接收
  • LOADING: 3 响应主体信息正在返回
  • DONE: 4 响应主体信息已经接收

如果在同步(false)的情况下,低版本 IE 是按照正常的同步编程顺序解析 1-4 。 在高版本下,看不到1-3的过程,直接走4 。
在执行1-4步的时候,每完成一次都会调用onreadystatechange,直到最后一步为4的时候,说明服务器已经有回应了。

xhr.send() 到底放在哪里合适?

如果是 onload ,放在 onload 的上面也行,下面也行。
如果是 onreadystatechange ,那么 send 放在事件的下面。
 原因:1. 能够多监听一步
    2. 低版本 IE 下如果把 send 放在事件的上面,并且在同步的时候,第4步监听不到。

总结:(同步的时候 send 放在事件的下面,异步的时候 send 放哪里都可以)

如果 IE 低版本:

  1. 创建ajax对象
  2. 填写地址
  3. 等待 (onreadystatechange)
  4. 发送 (send)

高版本:

  1. 创建ajax对象 (var xhr = new XMLHttpRequest)
  2. 填写地址 (xhr.open(‘get/post’,‘/ XXXX?xxx=’ + xxxx,默认:true / false))
  3. 发送 (send)
  4. 等待 (onload)
  5. 拿到返回信息

请求方式: GET系列{GET/HEAD/DELETE/OPTIONS} & POST系列

GET系列一般用于从服务器获取信息,POST系列一般用于给服务器推送信息;但是不论哪一种方式,都可以传递给服务信息,也可以从服务器获取信息,GET一般是给的少拿的多「如:获取某个用户信息」、POST一般是给的多拿的少「如注册新用户」

  • GET
  • HEAD:只获取响应头信息即可,响应主体信息不需要
  • DELETE:删除服务器上的某个资源信息
  • OPTIONS:CORS跨域资源共享的时候,作为一个试探性的请求进行处理
  • POST
  • PUT:和DELETE对应,常用于把一个资源文件上传到服务器上(或者发送给服务器的内容有很多)
  • ...

GET系列 VS POST系列

GET系列是基于 “问号传参” 把信息发送给服务器的xhr.open('GET','/api/list?xxx=xxx&xxx=xxx')
POST系列是基于 “请求主体” 把信息发送给服务器的xhr.send(请求主体信息)
基于请求头传递数据两者皆可以用!!

  1. GET传递给服务器的内容要少,因为URL长度是有最大限制的「IE-2KB左右 谷歌-8KB左右」,如果传递信息过多URL会超过最大限制,超过限制的部分会被自动截取掉,这样导致发给服务器的信息不全...
    POST理论上是不存在传输内容大小限制的,但是真实开发的时候,为了保证传输的效率,我们自己会进行限制

  2. GET没有POST安全,主要还是因为它传递给服务器的信息都在URL上,很容易被“黑客”劫持,这样导致信息泄露或被篡改,而POST请求主体传递的信息不容易被劫持!!
    解决:一些重要信息传递给服务器,我们要使用POST请求,基于请求主体,再进行加密,然后传递给服务器!!

  3. GET请求容易产生不可控的缓存{浏览器机制导致的},当两次及以上请求,每一次请求的地址和传递的参数信息都模一样的时候,很容易第二次获取的是第一次缓存下来的信息,这样其实是不好的!!
    解决:请求地址后面设置时间戳,保证每次请求的参数不一样即可
    xhr.open('GET', /api/list?lx=0&name=zf&_=${+new Date()});

请求过程

post请求的过程:
  1. 浏览器请求tcp连接(第一次握手)
  2. 服务器答应进行tcp连接(第二次握手)
  3. 浏览器确认,并发送post请求头(第三次握手,这个报文比较小,所以http会在此时进行第一次数据发送)
  4. 服务器返回100 Continue响应
  5. 浏览器发送数据
  6. 服务器返回200 OK响应
get请求的过程:
  1. 浏览器请求tcp连接(第一次握手)
  2. 服务器答应进行tcp连接(第二次握手)
  3. 浏览器确认,并发送get请求头和数据(第三次握手,这个报文比较小,所以http会在此时进行第一次数据发送)
  4. 服务器返回200 OK响应
    也就是说,目测get的总耗是post的2/3左右,这个口说无凭,网上已经有网友进行过测试。

三次握手,四次挥手

TCP(Transmission Control Protocol 传输控制协议)

posted @ 2018-12-04 18:19  真的想不出来  阅读(1375)  评论(0编辑  收藏  举报