HTTP:超文本传输协议(HyperText Transfer Protocol):规定web浏览器如何向web服务器提交或获取内容
1、HTTP请求的四大部分:
- 请求方法或’动作‘
- 正在请求的url
- 一个可选的请求头集合,其中可能包含身份验证信息
- 一个可选的请求主体
2、HTTP返回的三大部分:
- 一个数字和文字组成的状态码,用来显示请求的成功和失败
- 一个响应头集合
- 响应主体
3、使用HTTP:
通过new构造函数实例化一个XMLHttpRequest对象,也可以重用已经存在的XMLHttpRequest对象,这将终止之前通过该对象挂起的任何请求。
创建完之后调用open()方法指定url和方法;如果有请求头,可以通过setRequestHeader()来设置,多次调用设置多个请求头;通过send()指定可选的请求主体并发起请求,如果时get则没有请求主体,则参数为null
var request = new XMLHttpRequset();
var url = '...';
var msg = "要发送的内容体";
request.open('post',url);
request.setRequestHeader('Content-Type','text/plain;charset=UTF-8');
request.send(msg);
4、取得响应
通过XMLHttpRequset对象的属性和方法可以获取状态码、响应头、响应主体:
- status、statusText属性以数字和文本的形式返回HTTP状态码,
- getResponseHeader()和getAllResponseHeaders()能查询响应头
- responseText属性可以得到文本形式的响应主体。
为了在响应准备就绪时得到通知,必须监听XMLHttpRequst对象的readystatechange事件(XHR2规范定义了更多有用的事件,可以不再使用此事件,详情请见下文),当readyState属性发生变化时调用该事件。readyState属性的值如下:
常量 | 值 | 含义 |
UNSENT | 0 | open()尚未调用 |
OPENED | 1 | open()已调用 |
HEADERS_RECEIVED | 2 | 接收到头信息 |
LOADING | 3 | 接收到响应主体 |
DONE | 4 | 响应完成 |
var request = new XMLHttpRequset();
request.open('get',url);
//也可以使用addEventListener()来监听readystatechange事件
request.onreadystatechange = function(){
if(request.readyState === 4 && request.status === 200){
....
}
}
requset.send(null);
如果把false做为第三个参数传递给open()方法,则http请求会变成同步请求,此时不需要监听readystatechange事件,直接同步获取返回值就行了
5、编码请求主体
请求主体有以下几种:表单编码的请求、JSON编码的请求、XML编码请求、上传文件、multipart/form-data请求
- 表单编码的请求:对每个表单的key值和value值进行URL编码,使用等号将编码后的键和值分开,并用&符号分开键值对,如下:name=anne&age=12&sex=femail,表单数据编码格式有一个正式的MIME类型:application/x-www-form-urlencoded
- JSON编码的请求:需要使用JSON.stringify()方法将json对象转化为string类型,需要设置Content-Type:request.setRequsetHeader('Content-Type','application/json');
- XML编码的请求:将XML Document对象传递给send()方法,不需要设定Content-Type,浏览器将自动设置Content-Type
- 上传文件:使用<input type="file">元素选择文件时,表单将在它产生的POST请求主体中发送文件内容。input元素有一个files属性,它时file对象中的类数组对象。
var elts = document.getElementsByTagName('input');
for(var i=0; i<elts.length;i++){
var input = elts[i];
if(input.type !== 'file') continue;
var url = input.getAttribute('data-uploadto');
if(!url) continue;
input.addEventListener('change',function(){
var file = this.files[0];
if(!file) return;
var xhr = new XMLHttpRequest();
xhr.open('POST',url);
xhr.send(file);
},false)
}
- multipart/form-data请求:当HTML表单同时包含文件上传元素和其它元素时,浏览器不能使用普通的表单编码而必须使用称为“multipart/form-data”的特殊Content-Type来使用POST方法提交表单
6、XHR2定义的更多有用的事件
之前我们使用readystatechange事件来探测HTTP请求的过程,但XHR2规范定义了更多有用的事件,如下:
事件类型 | 说明 |
loadstart | 调用send方法时触发此事件 |
progress | 在正在加载服务器的响应时,触发此事件,通常每隔50ms触发一次,当请求快速完成时,可能不会触发此事件。可以通过此事件来获取下载的进度:此事件的事件对象包含以下属性:loaded:目前传输的字节数值;total:"Content-Length"头传输的数据的整体长度;lengthComputable:如果知道内容长度,则为true,否则为false,所以使用进度时,要先判断此属性 |
timeout | 当请求超时,会触发此事件 |
abort | 当请求被终止时,触发此事件 |
error | 请求发生错误时 |
TIPS:以上为响应会触发的事件,以下介绍上传进度事件 | |
XMLHttpRequest对象有upload属性,它是一个对象,有onprogress和onload方法,以此来监听上传进度和上传完成事件,实例如下: |
var xhr = new HttpRequest();
var body="需要上传的文件";
xhr.open('POST',url);
xhr.upload.onprogress = function(e){
if(e.lengthComputable){ //是否知道数据长度
var loaded = e.loaded; //已上传的数据
var total = e.total; //上传文件的总大小
}
}
xhr.upload.onload = function(){
//上传完成时触发此事件
}
xhr.send(body)
7、终止请求和超时:
abort()方法:调用XMLHttpRequest对象的的abort方法可以终止请求,此时将调用XMLHttpRequest对象的abort事件
timeout属性:设置超时时间,单位为毫秒,当超时时会调用timeout事件。
8、跨域HTTP请求
CORS:
XHR2通过在HTTP响应中选择发送合适的CORS(Cross-Origin Resource Sharing,跨域资源共享)允许跨域访问网站。跨域请求通常也不会包含其它任何的用户证书:cookie和HTTP身份验证令牌(token)通常不会做为请求的内容部分发送且任何做为跨域响应来接收的cookie都会丢弃。
JSONP:
<script>元素可以做为一种AJAX传输机制:值需要设置<script>元素的src属性,(如果它还没有插入到documen中,需要插入进入),然后浏览器就会发送一个HTTP请求以下载src属性所指向的url,使用此方法的一个主要原因是它不受同源策略的影响,因此可使用它们从其它的服务器请求数据,第二个原因是包含JSON编码数据的响应体会自动解码(即自动执行)。
这种使用<script>元素作为AJAX传输的技术称为JSONP,若HTTP请求所得到的响应数据是经过JSONP编码的,则适合使用该技术。
当<script>元素被调用数据时,响应内容必须用js函数名和圆括号包裹起来,如handleResponse([1,2,{...}]);
为了可行起见,我们必须通过某种方式告诉服务,它正在从一个<script>调用,必须返回一个JSONP响应,而不是JSON响应:通常我们是在URL中添加一个查询参数来实现:如追加:?jsonp=函数名:客户端定义一个函数名为此参数值的函数,响应返回时用这个函数去填充响应。另外一个常见的参数名是callback
function getJSONP(url,callback){
var cbnum = "cb" +getJSONP.counter++;
var cbname = 'getJSONP.'+cbnum; //作为JSONP函数的属性
if(url.indexOf('?') === -1){
url+='?jsonp='+cbname;
}else{
url += '&jsonp'+cbname;
}
var script = document.creatElement('script');
getJSONP[cbnum] = function(response){
try{
callback(response);
}
finally{
delete getJSONP[cbname];
script.parentNode.removeChild(script);
}
}
script.src = url;
document.body.appendChild(srcipt);
}
getJSONP.counter = 0;