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 的模型叫 电话模式
- 先有一个电话 创建ajax对象
- 输入号码(拨号) 填写请求地址 xhr.open("请求的方式","url地址"+具体字段,请求异步默认为true)
- 发送 send()
- 等待 xhr.onload
- 成功接收 在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 低版本:
- 创建ajax对象
- 填写地址
- 等待 (onreadystatechange)
- 发送 (send)
高版本:
- 创建ajax对象 (var xhr = new XMLHttpRequest)
- 填写地址 (xhr.open(‘get/post’,‘/ XXXX?xxx=’ + xxxx,默认:true / false))
- 发送 (send)
- 等待 (onload)
- 拿到返回信息
请求方式: 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(请求主体信息)
基于请求头传递数据两者皆可以用!!
-
GET传递给服务器的内容要少,因为URL长度是有最大限制的「IE-2KB左右 谷歌-8KB左右」,如果传递信息过多URL会超过最大限制,超过限制的部分会被自动截取掉,这样导致发给服务器的信息不全...
POST理论上是不存在传输内容大小限制的,但是真实开发的时候,为了保证传输的效率,我们自己会进行限制 -
GET没有POST安全,主要还是因为它传递给服务器的信息都在URL上,很容易被“黑客”劫持,这样导致信息泄露或被篡改,而POST请求主体传递的信息不容易被劫持!!
解决:一些重要信息传递给服务器,我们要使用POST请求,基于请求主体,再进行加密,然后传递给服务器!! -
GET请求容易产生不可控的缓存{浏览器机制导致的},当两次及以上请求,每一次请求的地址和传递的参数信息都模一样的时候,很容易第二次获取的是第一次缓存下来的信息,这样其实是不好的!!
解决:请求地址后面设置时间戳,保证每次请求的参数不一样即可
xhr.open('GET',/api/list?lx=0&name=zf&_=${+new Date()}
);
请求过程
post请求的过程:
- 浏览器请求tcp连接(第一次握手)
- 服务器答应进行tcp连接(第二次握手)
- 浏览器确认,并发送post请求头(第三次握手,这个报文比较小,所以http会在此时进行第一次数据发送)
- 服务器返回100 Continue响应
- 浏览器发送数据
- 服务器返回200 OK响应
get请求的过程:
- 浏览器请求tcp连接(第一次握手)
- 服务器答应进行tcp连接(第二次握手)
- 浏览器确认,并发送get请求头和数据(第三次握手,这个报文比较小,所以http会在此时进行第一次数据发送)
- 服务器返回200 OK响应
也就是说,目测get的总耗是post的2/3左右,这个口说无凭,网上已经有网友进行过测试。