AJAX

AJAX

Asynchronous JavaScript + XML(异步JavaScript和XML)在 Ajax 出现之前页面上数据发生改变的话就需要重新加载整个页面。而 Ajax 可以只对内容变化的区域进行数据的更新。使用Ajax可以减少与服务器数据的交互,从而提高效率,改善用户体验。

尽管X在Ajax中代表XML, 但由于JSON的许多优势,比如更加轻量以及作为Javascript的一部分,目前JSON的使用比XML更加普遍。JSON和XML都被用于在Ajax模型中打包信息。

浏览器与服务器之间的关系

  • 服务器 存储编写好的网页程序。服务器在网络端,用户不可见。
  • 浏览器 用户电脑上的浏览器可以通过网络获取页面程序,并将页面显示。

协议

协议是定义了数据如何在计算机内和之间进行交换的规则的系统。设备之间通信要求设备接受正在交换的数据的格式。定义格式的一组规则称之为协议。

TCP/IP

  • TCP:

    • 传输控制协议(TCP)是主要的网络协议之一。它使两台主机能够建立连接并交换数据流。TCP 能保证数据的交付,维持数据包的发送顺序。
    • TCP 使用三次握手来建立一个连接和四次挥手来中断一个连接。


  • IP:

    • IP地址是分配给连接到使用Internet协议的网络的每个设备的一串数字。
    • IPv6 是当前版本的互联网(Internet)通信协议(protocol)。IPv6 正在慢慢地取代 IPv4,因为 IPv6 允许使用更多不同的 IP 地址。
      • ipv4: 192.168.6.164
      • ipv6: fe80::f070:3dd3:9f9b:5b7%21
    • windows 查看IP ipconfig linux查看ifconfig
  • 域名:IP地址与域名是一对多的映射关系,一个IP地址可以对应多个域名。

  • 端口:计算中的每一个软件都应该有一个唯一的端口号。

    • 端口号:唯一(计算机中)的端口号(0 - 65535 0-1023系统占用,1024-65535)
    • 端口号如果是80 在浏览器地址栏可以不用输入

HTTP

超文本传输协议(HTTP)是一个用于传输超媒体文档(例如 HTML)的应用层协议。它是为 Web 浏览器与 Web 服务器之间的通信而设计的,但也可以用于其他目的。HTTP 遵循经典的客户端-服务端模型,客户端打开一个连接以发出请求,然后等待它收到服务器端响应。HTTP 是无状态协议,这意味着服务器不会在两个请求之间保留任何数据(状态)。该协议虽然通常基于 TCP/IP 层,但可以在任何可靠的传输层上使用;也就是说,不像 UDP,它是一个不会静默丢失消息的协议。

HTTP (The HyperText Transfer Protocol,超文本传输协议) 是用于在 Web 上传输超媒体文件的底层 协议 ,最典型场景的是在浏览器和服务器之间传递数据,以供人们浏览。现行的 HTTP 标准的版本是 HTTP/2。

“http://” 称为 “schema”,是 URI 的组成部分,一般位于网络地址的开头。以“https://developer.mozilla.org”为例,该地址说明请求文档时使用 HTTP 协议;这里的 https 代指 HTTP 协议的安全版本,即 SSL (或称 TLS)

HTTP 是基于文本的(所有的通信都以纯文本的形式进行) 以及无状态的 (当前通信状态不会发现以前的通信状态),该特性极大方便了在www上浏览网页的人。除此之外,HTTP也可以用于构建服务器之间交互的 REST web 服务,以及使得网站内容更加动态化的 AJAX 请求。

HTTP请求方式

请求方式参考

  1. GET: GET方法请求一个指定资源的表示形式. 使用GET的请求应该只被用于获取数据.
  2. HEAD: HEAD方法请求一个与GET请求的响应相同的响应,但没有响应体.
  3. POST: POST方法用于将实体提交到指定的资源,通常导致在服务器上的状态变化或副作用.
  4. PUT: PUT方法用请求有效载荷替换目标资源的所有当前表示。
  5. DELETE: DELETE方法删除指定的资源。
  6. CONNECT: CONNECT方法建立一个到由目标资源标识的服务器的隧道。
  7. OPTIONS: OPTIONS方法用于描述目标资源的通信选项。
  8. TRACE: TRACE方法沿着到目标资源的路径执行一个消息环回测试。
  9. PATCH: PATCH方法用于对资源应用部分修改。

HTTP状态码

HTTP 响应状态代码指示特定 HTTP 请求是否已成功完成。响应分为五类:信息响应(100–199),成功响应(200–299),重定向(300–399),客户端错误(400–499)和服务器错误 (500–599)。
HTTP状态码表

AJAX 的基本使用

编写一个ajax请求分为四部

  • 创建请求对象
  • 设置请求参数
  • 发送请求
  • 接收响应数据
  1. 创建 Ajax 请求对象:XMLHttpRequest
1
2
3
4
5
6
7
8
// 1. 创建 ajax 请求对象。
var xhr = null;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
}else{
// 兼容 IE5/6
xhr = new ActiveXObject("Microsoft.XMLHTTP")
}
  1. 设置请求参数: xhr.open()
    使用 open()设置请求参数,该函数有三个参数:
    • 参数1:请求方式POST/GET
    • 参数2:请求的地址URL
    • 参数3:是否异步请求,true/false。设置为false时为同步程序将会阻塞,不建议使用。

get请求示例:

1
xhr.open("get", "/ajax/server.php?name=小明&age=19", true);

get请求的参数直接跟在URL后面。

post请求示例:

1
2
3
4
5
xhr.open("post", "/ajax/server.php", true);
//设置请求头
xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
// 提交给服务器,并且设置请求参数。
xhr.send("name=小明&age=19");

post 请求必须要设置请求头,请求参数在提交给服务器的send()函数中设置。

媒体类型媒体类型 Content-type取值参考 media-types

setRequestHeader()设置HTTP请求头部的方法 ,您必须在 open() 之后、send() 之前调用 setRequestHeader() 方法。

  1. 将请求提交给服务器:xhr.send()
1
xhr.send("name=小明&age=19");

send()的参数中可以设置请求要传递给服务器的数据。要注意,该参数只有在POST请求时才有效。

get或者是post请求参数中如果有特殊字符如:”& \ % = “可以使用编码函数与解码函数escape(String s)unescape(String s) 对请求参数进行编码的转换。

  1. 等待服务器响应:xhr.onreadystatechange()
1
2
3
4
5
xhr.onreadystatechange = function () {
if (4 == xhr.readyState && 200 == xhr.status) {
alert(xhr.responseText);
}
}
  • xhr.readyState
    • 0: 请求未初始化
    • 1: 服务器连接已建立
    • 2: 请求已接收
    • 3: 请求处理中
    • 4: 请求已完成,且响应已就绪
  • xhr.status: HTTP状态码
  • xhr.responseText: 字符串格式的响应内容。

运行环境

  • phpStudy下载
    • phpStudy 是一款集成的服务器端环境,解压后可直接使用
    • 解压路径中不能包含空格和中文

编写的 ajax代码需要在服务器环境下运行

  • 如果请求的文件是 .json文件 需要注意只能使用 get请求方式

基于 promise ajax的封装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
/**
* ajax
* @param {Object} args
* args.url 请求路径
* args.method 请求方式,可选的
* args.data 请求数据,json格式{},可选的
*/

function ajax(args) {
if (!args.method) {
args.method = "get"
}
const promise = new Promise(function (resolve, reject) {
let xhr = null;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else {
xhr = new ActiveXObject("Microsoft.XMLHTTP")
}
let oData = new FormData();
for (const key in args.data) {
oData.append(key, args.data[key])
}
xhr.open(args.method, args.url, true);
xhr.send(oData);
xhr.onreadystatechange = function () {
if (4 == xhr.readyState && 200 == xhr.status) {
try {
switch (args.method) {
case "head":
case "Head":
return resolve({
statusText: this.statusText,
status: this.status,
url: this.responseURL,
readyState: this.readyState
})
default:
return resolve(JSON.parse(this.response))
}

} catch (error) {
resolve(this.response)
}

} else if (4 == xhr.readyState) {
reject(new Error(xhr.status));
}
}
})

return promise;

}

跨域

跨域是指一个域下的文档或脚本试图去请求另一个域下的资源,这里跨域是广义的

广义的跨域:

  1. 资源跳转: A链接、重定向、表单提交
  2. 资源嵌入: link script img frame等dom标签,还有样式中background:url()``、@font-face()等文件外链
  3. 脚本请求: js发起的ajax请求、dom和js对象的跨域操作等

狭义的跨域:

前端部分其实我们通常所说的跨域是狭义的,是由浏览器同源策略限制的一类请求场景。

  • 同源策略:
    同源策略/SOP(Same origin policy)是一种约定,由Netscape公司1995年引入浏览器,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。所谓同源是指”协议+域名+端口”三者相同,即便两个不同的域名指向同一个ip地址,也非同源。

常见的跨域场景

跨域

常见的跨域处理

  • jsonp
    Jsonp(JSON with Padding) ,jsonp解决跨域问题时并不会使用ajax,而是利用函数的调用将数据从服务器端传入到客户端(浏览器),要想实现jsonp必须浏览器端与服务器端共同编写代码

    • 浏览器端: 编写 数据处理函数,该函数的参数为接收服务器端传入的数据,关于数据使用需要根据情况编写
    • 服务器端: 返回在浏览器端编写的 数据处理函数 调用,在参数列表中需要传入相应的数据
    • <script src=''> 加载服务器端代码。<script>标签在加载资源文件时不存在跨域的问题。因为加载的服务器端代码是数据处理函数的调用所以将立即触发该函数的执行

    jsonp只能get请求

  • CORS跨源资源分享

    CORS是跨源资源分享(Cross-Origin Resource Sharing)的缩写。它是W3C标准,是跨源AJAX请求的根本解决方法。相比JSONP只能发GET请求,CORS允许任何类型的请求。CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。

    整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。

    因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。

    服务端设置Access-Control-Allow-Origin
    这种方式只要服务端把response的header头中设置Access-Control-Allow-Origin为请求当前域名下数据的域名即可。一般情况下设为 * 即可。

1
2
3
<?php
//设置可跨域
header('Access-Control-Allow-Origin:*');
  • 代理服务器
  • 便于用户调试可以关闭浏览器的跨域检测
    以google浏览器为例:右键 > 属性 > 快捷方式 > 目标栏结束添加--disable-web-security --user-data-dir=C:\MyChromeDevUserData

    重启浏览器后显示以下提示表示设置成功:

文件上传

使用 form 控件

1
2
3
4
5
<form class="upload" onsubmit="uploadPicClick"   method="POST" enctype="multipart/form-data">
<input type="hidden" name="MAX_FILE_SIZE" value="3000000">
<input type="file" name="pic">
<input type="submit" name="" value="上传">
</form>
  • 使用ajax上传文件,form表单中的action属性不需要写。
  • method必须是 POST方式提交表单。
  • enctype值必须为 multipart/form-data,multipart/form-data表示表单中的数据不会被编码。
  • 隐藏域中 name=”MAX_FILE_SIZE” value=”3000000” 用来限制上传文件的大小。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
let upload = document.querySelector(".upload");
upload.onsubmit = function (ev) {

// 获取表单数据
let oData = new FormData(upload);
//添加字段
oData.append("picDir", "img1");
let xhr = null;
if (window.XMLHttpRequest) {
xhr = new XMLHttpRequest();
} else {
xhr = new ActiveXObject("Microsoft.XMLHTTP")
}
xhr.open("POST", "http://192.168.7.31/ajax/upload.php", true);
xhr.send(oData);
xhr.onreadystatechange = function () {
if (4 == xhr.readyState && 200 == xhr.status) {
if ("uploadSuccess" === xhr.responseText) {
alert("上传成功!");
} else if ("uploadError" === xhr.responseText) {
alert("上传失败!");
}
document.querySelector('[type="file"]').value = ''
}
}
ev.preventDefault(); // 兼容标准浏览器
// window.event.returnValue = false; // 兼容IE6~8
return false;
}

  • 使用ajax请求数据必须阻止表单的默认事件。

  • 使用FormData()获取表单数据,append()可以追加表单字段。

  • 必须使用post请求。

  • 不能设置请求头xhr.setRequestHeader();

FormData

FormData 接口提供了一种表示表单数据的键值对的构造方式,经过它的数据可以使用了XMLHttpRequest.send() 方法送出。

  1. 常用方法:formData.append(name, value, filename)

    | 参数 | 描述 |
    | :———-: | :—————————————————————————————-: |
    | name | value中包含的数据对应的表单名称。 |
    | value | 表单的值。可以是USVString 或 Blob (包括子类型,如 File)。 |
    | filename | 传给服务器的文件名称 , 当一个 Blob 或 File 被作为第二个参数的时候, Blob 对象的默认文件名是 “blob”。 File 对象的默认文件名是该文件的名称。 |

Fetch

Fetch是 XMLHttpRequest 的替代方法

Fetch支持 Promise

Fetch 参考文档

当接收到一个代表错误的 HTTP 状态码时,从 fetch()返回的 Promise 不会被标记为 reject, 即使该 HTTP 响应的状态码是 404 或 500。相反,它会将 Promise 状态标记为 resolve (但是会将 resolve 的返回值的 ok 属性设置为 false ),仅当网络故障时或请求被阻止时,才会标记为 reject。

get

1
2
3
4
5
6
7
8
9
10
11
let url = 'http://192.168.6.48/ajax/server2.php?name=list'
fetch(url)
.then(res=>{ //返回响应对象
return res.json() //将响应对象转换为json
})
.then(res=>{
console.log( res )
})
.catch(err=>{
console.log( err )
})

post

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
let url = 'http://192.168.6.48/ajax/server2.php'
fetch(url, {
method: 'POST',
body: 'name=list&age=89',
headers: {
'Content-type': 'application/x-www-form-urlencoded'
},
mode: 'cors',
})
.then(res => { //返回响应对象
return res.json() //将响应对象转换为json
})
.then(res => {
console.log(res)
})
.catch(err => {
console.log(err)
})

mode:请求的模式

  1. mode: 'no-cors' 不可跨域
  2. mode: 'cors' 可跨域
  3. mode: 'same-origin' 同源策略

post请求时三种传参方式

  1. 字符串形式,注意:需要设置请求头

    1
    2
    3
    4
    5
    6
    7
    8
    9
    let url = 'http://192.168.6.48/ajax/server2.php'
    fetch(url, {
    method: 'POST',
    body: 'name=list&age=89',
    headers: {
    'Content-type': 'application/x-www-form-urlencoded'
    },
    mode: 'cors',
    })
  1. 使用 new FormData()

    1
    2
    3
    4
    5
    6
    7
    8
    let fd = new FormData()
    fd.append('name', 'list')

    fetch(url, {
    method: 'POST',
    body: fd,
    mode: 'cors',
    })
  2. 使用

    1
    2
    3
    4
    5
    6
    7
    let param = new URLSearchParams()
    param.append("name", "list")
    fetch(url, {
    method: 'POST',
    body: param,
    mode: 'cors',
    })

fetch 中cookie

Fetch 不会接受跨域 cookies。

fetch 默认不会发送 cookies。(自 2017 年 8 月 25 日以后,默认的 credentials 政策变更为 same-origin。)

1
2
3
fetch('https://example.com', {
credentials: 'include' //设置携带cookie的策略
})

credentials 3个取值:

  1. credentials: 'include' 为了让浏览器发送包含凭据的请求(即使是跨域源)
  2. credentials: 'same-origin' 同源
  3. credentials: 'omit' 不包含cookie

axios

axios中文参考文档

  1. 安装 npm install axios
  2. cdn <script src="https://unpkg.com/axios/dist/axios.min.js"></script>

特点

1
Axios 是一个基于 promise 的 HTTP 库
  • 从浏览器中创建 XMLHttpRequests
  • 从 node.js 创建 http 请求
  • 支持 Promise API
  • 拦截请求和响应
  • 转换请求数据和响应数据
  • 取消请求
  • 自动转换 JSON 数据
  • 客户端支持防御 XSRF

get

1
2
3
4
5
6
7
axios.get('http://192.168.6.48/ajax/server2.php?name=list')
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});

post

1
2
3
4
5
6
7
8
9
let param = new URLSearchParams()
param.append("name", "list")
axios.post('http://192.168.6.48/ajax/server2.php', param)
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});

post 请求时三种传参方式:

  1. 使用 new URLSearchParams()

    1
    2
    3
    let param = new URLSearchParams()
    param.append("name", "list")
    axios.post('http://192.168.6.48/ajax/server2.php', param)
  2. 使用 new FormData ()

    1
    2
    3
    let fd = new FormData ()
    fd.append('name',"list")
    axios.post('http://192.168.6.48/ajax/server2.php', fd)
  1. 字符串

    1
    axios.post('http://192.168.6.48/ajax/server2.php',  "name=list"  )

拦截器

在请求或响应被 thencatch 处理前拦截它们。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 添加请求拦截器
axios.interceptors.request.use(function (config) {
// 在发送请求之前做些什么
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
})

// 添加响应拦截器
axios.interceptors.response.use(function (response) {
// 对响应数据做点什么
return response;
}, function (error) {
// 对响应错误做点什么
return Promise.reject(error);
});

拦截器需要写在请求发送之前

删除拦截器

1
2
3
4
// 接收拦截器ID
const myInterceptor = axios.interceptors.request.use(function () {/*...*/});
// 删除指定的拦截器
axios.interceptors.request.eject(myInterceptor);