Ⅰ- 壹 - 什么是Ajax
Ajax
= 异步JavaScript
和XML
。Ajax
不是新的编程语言,而是一种使用现有标准的新方法。- 通过在后台与服务器进行少量数据交换,
Ajax
可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新。 - Ajax技术核心是XMLHttpRequest对象(简称XHR)XHR对象可以直接实例化XMLHttpRequest即可。
一 存在以下缺点:
-
受同源策略的限制,不能发送跨域请求;
-
不能发送二进制文件(如图片、视频、音频等),只能发送纯文本数据;
-
在发送和获取数据的过程中,无法实时获取进度信息,只能判断是否完成;
-
无法进行操作的后退,即不支持浏览器的页面后退。
-
对搜索引擎的支持比较弱。
-
可能会影响程序中的异常处理机制。
-
安全问题,对一些网站攻击,如csrf、xxs、sql注入等不能很好地防御。
二 Ajax优点:
- 可以发送跨域请求,在服务端允许的情况下;
- 支持发送和接收二进制数据;
- 新增formData对象,支持发送表单数据;
- 发送和获取数据时,可以获取进度信息;
- 可以设置请求的超时时间;
- 页面无刷新,在页面内与服务器通信,减少用户等待时间,增强了用户体验。
- 使用异步方式与服务器通信,响应速度更快。
- 可以把一些原本服务器的工作转接到客户端,利用客户端闲置的能力来处理,减轻了服务器和带宽的负担,节约空间和宽带租用成本。
- 基于标准化的并被广泛支持的技术,不需要下载插件或者小程序。
三 创建Ajax四步
我们与服务器通信的API就是XMLHttpRequest。
那么我们都需要那些步骤来通信呢,简单理解一共只有4步。
-
新建XMLHttpRequest对象
var request=new XMLHttpRequest();
IE 7以下 var request=new ActiveXObject(“Microsoft.XMLHTTP”); -
打开要发送的地址通道。
request.open(“GET”,地址,同步/异步); -
给XMLHttpRequest对象增加侦听器,用来侦听各种情况,包括各种链接状态
request.addEventListener(“load”,侦听函数)发送数据给打开的地址, -
如果没有要发送的内容直接send()
request.send();
Ⅱ - 贰 - Ajax的方法
一 xhr.open()
通过XMLHttpRequest ,你可以很容易的取回一个URL上的资源数据. 尽管名字里有XML, 但 XMLHttpRequest 可以取回所有类型的数据资源,并不局限于XML。 而且除了HTTP ,它还支持file 和 ftp 协议.
因此不要局限于网络通信,他同样也可以做当前服务中的文件调用
xhr.Open()参数有:
xhr.open(“Method ”,“URL”,async,“user”,“password”)
参数 | 作用 |
---|---|
method | 发送请求的方式,可选的参数有:GET 、POST 、PUT 、DELETE |
URL | 要发送的URL路径,可以使用绝对路径和相对路径。也可以用来请求本地文件标注a |
async | 请求是否要被异步处理。也可以不写,默认为true。标注b |
user | 访问地址的用户名,可选参数吗,默认参数为空string. |
password | 访问地址的密码,可选参数吗,默认参数为空string. |
标注a
:
url地址是一个比较强大的内容,如果给服务器传参不需要加密的话,可以通过url来进行传参,通常传参的方法是
http://地址:端口/文件名?参数1=值1&参数2=值2;也可以用来请求本地文件
标注b
:
-
true,脚本处理会在send()发送之后继续处理,即异步处理。
-
false,在继续脚本处理之前,脚本会等待某个响应,即同步处理。
小结:
1、URL参数中:
GET是带参数、POST不带参数,如果希望每次请求都是最新的就需要加时间戳
URL地址中通qza 过目录方式带入请求的类型
async 默认是true,异步。如果设置false,是同步,不需要事件侦听
user password 访问地址的用户名密码
二 xhr.send()
发送请求。如果该请求是异步模式(默认),该方法会立刻返回。相反,如果请求是同步模式,则直到请求的响应完全接受以后,该方法才会返回。
注意:所有相关的事件绑定必须在调用 send() 方法之前进行。
xhr.send(ArrayBuffer data);类型化数组
xhr.send(Blob data);二进制大对象,是一个可以存储二进制文件的容器。
xhr.send(Document data); 文档对象
xhr.send(DOMString? data); 文本数据
xhr.send(FormData data); 数据对象,可以直接封装内容
var form=document.querySelector("form");
form.addEventListener("submit",submitHandler);
function submitHandler(e){
e.preventDefault();
//新建FormData对象,将form作为参数传进去
let fd=new FormData(form);
let xhr=new XMLHttpRequest();
xhr.addEventListener("load",loadHandler);
xhr.open("POST","http://127.0.0.1:4006");
//可以直接发送给服务端,但是要注意,服务端需要对FormData做处理才可以使用
xhr.send(fd);
}
function loadHandler(e){
console.log(this.response);
}
(1) FormData()
XMLHttpRequest Level 2添加了一个新的接口FormData
.利用FormData对象
,我们可以通过JavaScript用一些键值对来模拟一系列表单控件,我们还可以使用XMLHttpRequest的send()
方法来异步的提交这个"表单".比起普通的ajax,使用FormData
的最大优点就是我们可以异步上传一个二进制文件.
- 可以通过构造函数创建添加
var formData = new FormData();
formData.append("username", "EricXie");
formData.append("age", "30");
formData.append("sex", "men");
xhr.send(formData);
//使用 for of 来遍历
for(let value of formData){
console.log(value);
}
- 可以获取表单中的数据进行添加
//html部分
<form>
<input type="text" name="user">
<input type="text" name="password">
<button type="submit">提交</button>
</form>
<script>
var form=document.querySelector("form");
form.addEventListener("submit",submitHandler);
function submitHandler(e){
e.preventDefault();
var xhr=new XMLHttpRequest();
xhr.addEventListener("load",loadHandler);
xhr.open("POST","http://localhost:4006");
xhr.send(new FormData(form));
}
function loadHandler(e){
}
</script>
小结:
- 如果是
POST
请求的话,传参则应该这么写xhr.send("name=niji");
或者xhr.send('{"user":"xietian","age":30}');
三 HTTP 头部(响应头/请求头)
HTTP客户程序(例如浏览器),向服务器发送请求的时候必须指明请求类型(一般是GET或者POST)。如有必
要,客户程序还可以选择发送其他的请求头。大多数请求头并不是必需的,但Content-Length除外。 对于POST请求来说Content-Length必须出现。请通过百度等搜索引擎搜索该内容学习。这部分内容在以后实际应用中有很多是需要使用的。
-
GET方式允许发送自定义消息头,POST不允许、 发送自定义消息头时,必须在服务端设置响应头跨域同意
Access-Control-Allow-Headers:"*"
-
请求消息,必须在open( )后,send( )前写入如果ajax与php通信使用POST方法时,必须这样写入消息头,PHP才可以解析POST数据
方法 | 简介 |
---|---|
xhr.getResponseHeader() | 获取头部指定的属性值 |
xhr.etAllResponseHeaders() | 获取所有头部属性 |
xhr.setRequestHeader() | 设置头部属性,必须在open以后,send以前写入 |
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZO2S8hVu-1596878281104)(C:\Users\幻影旅团\AppData\Roaming\Typora\typora-user-images\image-20200807202900769.png)]
var xhr = new XMLHttpRequest();
xhr.addEventListener("load", loadHandler);
xhr.open("GET", "http://10.9.65.239:4006?user=nicai&age=30");
// 这个请求头是让PHP可以解析当前的POST数据
xhr.setRequestHeader("content-type", "application/x-www-form-urlencoded");
// GET方式允许发送自定义消息头,POST不允许
// 发送自定义消息头时,必须在服务端设置响应头跨域同意Access-Control-Allow-Headers:"*"
// xhr.setRequestHeader("abc","3");
xhr.send();
function loadHandler(e) {
// console.log(xhr.getAllResponseHeaders());//获取所有响应头
// console.log(xhr.getResponseHeader("content-type"));//获取指定的响应头
}
(1) 请求头信息
请求头 | 简述 |
---|---|
Accept | 客户端支持的数据类型 |
Accept-Charset | 客户端采用的编码 |
Accept-Encoding | 客户端支持的数据压缩格式 |
Accept-Language | 客户端的语言环境 |
Cookie | 客服端的cookie |
Host | 请求的服务器地址 |
Connection | 客户端与服务连接类型 |
If-Modified-Since | 上一次请求资源的缓存时间,与Last-Modified对应 |
If-None-Match | 客户段缓存数据的唯一标识,与Etag对应 |
Referer | 发起请求的源地址。 |
(2) 响应头信息
响应头 | 简述 |
---|---|
content-encoding | 响应数据的压缩格式。 |
content-length | 响应数据的长度。 |
content-language | 语言环境。 |
content-type | 响应数据的类型。 |
四 GET和POST的区别
- GET是从服务器上获取数据,POST是向服务器传送数据。
- GET把参数包含在URL中,POST通过request body传递参数。
- 对于GET方式,服务器端用Request.QueryString获取变量的值,对于POST方式,服务器端用Request.Form获取提交的数据。
- GET传送的数据量较小,不能大于2KB。post传送的数据量较大,一般被默认为不受限制。但理论上,IIS4中最大量为80KB,IIS5中为100KB。(这里有看到其他文章介绍GET和POST的传送数据大小跟各个浏览器、操作系统以及服务器的限制有关)
- GET安全性非常低,POST安全性较高。
- GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
- GET请求只能进行url编码,而POST支持多种编码方式。
五 创建Ajax、 node开启服务
(1) node开启服务 ajax.js
var http=require("http");
var querystring=require("querystring");
var server=http.createServer(function(req,res){
// 获取请求头消息
// console.log(req.headers.names);
var data="";
// POST方式获取客户端发来的消息,转换为字符串就可以得到
req.on("data",function(_data){
data+=_data;
});
req.on("end",function(){
if(req.url.indexOf("favicon.ico")>-1) return;
if(data.trim().length===0) data=req.url.split("?")[1];
else{
try{
data=JSON.parse(data);
}catch(error){
}
}
if(typeof data==="string"){
try{
data=querystring.parse(data);
}catch(error){
res.end("错误的消息");
return;
}
}
if(!data){
res.end("错误的消息");
return;
}
// 设置响应头
res.writeHead(200,{
"content-type":"text/html;charset=utf-8",//解决中文乱码问题
"Access-Control-Allow-Origin":"*",//地址跨域
"Access-Control-Allow-Headers":"*"//请求头跨域
})
res.write((data.user? data.user : "你没有user")+"欢迎光临");
res.end();
})
});
// 创建好的服务开启侦听,第一个参数是网络的端口号,第二个参数是网络的ip,第三个参数是开启后的回调函数
server.listen(4006,"localhost",function(){
console.log("服务已开启");
})
(2) 创建Ajax ajax.html
创建GET请求方式
<script>
var xhr=new XMLHttpRequest();//实例化Ajax
xhr.addEventListener("load",loadHandler);//绑定加载事件
xhr.open("GET","http://127.0.0.1:4006?user=WWW&age=30")//打开要发送的地址通道 GET请求方式
xhr.send();//请求结束
//加载事件函数
function loadHandler(e){
//接收服务器响应的数据
console.log(xhr.response);
}
</script>
创建POST请求方式
<script>
var xhr
try{
xhr=new XMLHttpRequest();
}catch(error){
xhr=new ActiveXObject("Microsoft.XMLHTTP");//IE7
}
xhr.addEventListener("load",loadHandler);
xhr.open("POST","http://localhost:4006");
xhr.send('{"user":"WWW","age":30}');
function loadHandler(e){
//接收服务器响应的数据
console.log(xhr.response);
}
</script>
Ⅳ - 肆 - Ajax的属性
一 属性简介
属性 | 描述 |
---|---|
onreadystatechange | 状态发生改变的时候,能触发一些事情。 |
readyState | 详情见标注a |
status | 数字返回状态,比如"OK"为200,"Not Found"为404等标注b |
statusText | 字符串返回状态,比如"OK","Not Found"等 |
responseText | 以字符串返回响应。 |
responseXML | 以XML返回响应。返回的是一个XML对象,可以用DOM进行解析 |
(1) 标注a
readyState
状态值 | 代表的状态释义 |
---|---|
0 | 未初始化的状态,代表XMLHttpRequest对象被创建之前 |
1 | 加载中的状态,open操作。 |
2 | 已加载的状态,send操作。 |
3 | 交互的状态,接收到了响应数据,但只有响应头,正文还没别接收。 |
4 | 完成的状态,所有的http响应接收完成。 |
(2) 标注b
status
1 信息 100-101
101:切换协议,服务器根据客户端的请求切换协议
2 成功 200-206
200:请求成功。一般用于GET与POST请求
3 重定向 300-307
301:永久重定向
302:临时重定向
303:与301类似。使用GET和POST请求查看
304:请求资源未修改,使用缓存
307:与302类似。使用GET请求重定向
4 客户端错误 400-417
404:客户端请求失败
408:请求超时
5 服务器错误 500-505
500:内部服务器错误,无法完成请求
505:服务器不支持请求的HTTP协议的版本,无法完成处理
用于请求数据的之前的验证
var xhr=new XMLHttpRequest();
xhr.addEventListener("readystatechange",readyHandler);
xhr.open("GET","http://localhost:4006?user=xietian&age=30");
xhr.send();
function readyHandler(e){
// xhr.status 响应消息的状态
if(xhr.readyState===4 && xhr.status===200){
console.log(xhr.response);
}
}
Ⅴ - 伍 - Ajax 使用
一 load用于本地加载文件
- 加载本地文件必须使用GET方式
(1) 本地加载JSON文件
获取到数据之后可以进行DOM操作 ,加载的数据直接可以咋配置文件修改
var xhr=new XMLHttpRequest();
xhr.addEventListener("load",loadHandler);
xhr.open("GET","./config/a.json");
xhr.send();
function loadHandler(){
var obj=JSON.parse(xhr.response);
document.documentElement.style.backgroundColor=obj.backgroundColor;
}
a.json
{
"backgroundColor": "red"
}
二 promise封装ajax
这利用到了第三方模块querystring.js
querystring从字面上的意思就是查询字符串,一般是对http请求所带的数据进行解析。querystring模块只提供4个方法,在我看来,这4个方法是相对应的。
parse(str),默认以固定&=格式,解析路径,得到key/value的对象。
stringify(),系列化,把上述对象载拼成一个字符串。
第一种
<script type="module">
import QueryString from "./js/QueryString.js";
function ajax(data,type="GET"){
if(type!=="GET") type="POST";
return new Promise(function(resolve,reject){
let getData="";
let postData="";
if(type==="GET"){
getData="?"+QueryString.stringfiy(data);
}else{
postData=QueryString.stringfiy(data);
}
let xhr=new XMLHttpRequest();
xhr.open(type,"http://127.0.0.1:8001"+getData);
xhr.onload=function(){
resolve(xhr.response);
}
xhr.onerror=function(){
reject("地址错误");
}
xhr.send(postData);
})
}
//使用
ajax({a:3,b:5}).then(function(data){
console.log(data);
}).catch(function(msg){
console.log(msg)
})
</script>
第二种
<script type="module">
import QueryString from "./js/QueryString.js";
function ajax(url,data,method="GET",type="query"){
return new Promise(function(resolve,reject){
if(type.toLowerCase()==="query") data=QueryString.stringify(data);
else if(type.toLowerCase()==="json") data=JSON.stringify(data);
var xhr=new XMLHttpRequest();
xhr.onreadystatechange=function(){
if(xhr.readyState===4 && xhr.status===200){
resolve(xhr.response);
}else if(xhr.readyState===4 && xhr.status!==200){
reject(xhr.status);
}
}
xhr.open(method,url+"?"+(method.toLowerCase()==="get" ? data : ""));
xhr.send((method.toLowerCase()==="get" ? "" : data));
})
}
//使用
ajax("http://localhost:4006",{user:"xietian",age:30},"POST","JSON").then(function(res){
console.log(res);
})
</script>
querystring.js
export default class QueryString {
static stringify(obj, sep, eq, name) {
sep = sep || '&';
eq = eq || '=';
if (obj === null) {
obj = undefined;
}
if (typeof obj === 'object') {
return Object.keys(obj).map(function (k) {
var ks = encodeURIComponent(QueryString.stringifyPrimitive(k)) + eq;
if (Array.isArray(obj[k])) {
return obj[k].map(function (v) {
return ks + encodeURIComponent(QueryString.stringifyPrimitive(v));
}).join(sep);
} else {
return ks + encodeURIComponent(QueryString.stringifyPrimitive(obj[k]));
}
}).join(sep);
}
if (!name) return '';
return encodeURIComponent(QueryString.stringifyPrimitive(name)) + eq +
encodeURIComponent(QueryString.stringifyPrimitive(obj));
}
static stringifyPrimitive(v) {
switch (typeof v) {
case 'string':
return v;
case 'boolean':
return v ? 'true' : 'false';
case 'number':
return isFinite(v) ? v : '';
default:
return '';
}
}
static parse(qs, sep, eq, options) {
sep = sep || '&';
eq = eq || '=';
var obj = {};
if (typeof qs !== 'string' || qs.length === 0) {
return obj;
}
var regexp = /\+/g;
qs = qs.split(sep);
var maxKeys = 1000;
if (options && typeof options.maxKeys === 'number') {
maxKeys = options.maxKeys;
}
var len = qs.length;
// maxKeys <= 0 means that we should not limit keys count
if (maxKeys > 0 && len > maxKeys) {
len = maxKeys;
}
for (var i = 0; i < len; ++i) {
var x = qs[i].replace(regexp, '%20'),
idx = x.indexOf(eq),
kstr, vstr, k, v;
if (idx >= 0) {
kstr = x.substr(0, idx);
vstr = x.substr(idx + 1);
} else {
kstr = x;
vstr = '';
}
k = decodeURIComponent(kstr);
v = decodeURIComponent(vstr);
if (!QueryString.hasOwnProperty(obj, k)) {
obj[k] = v;
} else if (Array.isArray(obj[k])) {
obj[k].push(v);
} else {
obj[k] = [obj[k], v];
}
}
return obj;
}
static hasOwnProperty(obj, prop) {
return Object.prototype.hasOwnProperty.call(obj, prop);
}
}
0 - 0 - 知识点:
一 URI编码格式转换
地址栏中?后面会出现类似%E4%BD%A0%E5%A5%BD
一串东西被称之为 URI编码格式
console.log(encodeURIComponent("你好"));//转换为URI编码格式
console.log(decodeURIComponent("%E4%BD%A0%E5%A5%BD"));//将URI编码格式转为字符
二 Ajax中的事件
事件要写在open()和send()前面。
load:用于本地数据的加载
timeout:设置超时事件
readystatechange:事件先于 load 事件执行