1. Ajax 基础
1.1 传统网站中存在的问题
-
网速慢的情况下,页面加载时间长,用户只能等待
-
表单提交后,如果一项内容不合格,需要重新填写所有表单内容
-
页面跳转,重新加载页面,造成资源浪费,增加用户等待时间
1.2 Ajax 概述
Ajax:标准读音 [ˈeɪˌdʒæks] ,中文音译:阿贾克斯
它是浏览器提供的一套方法,可以实现页面无刷新更新数据,提高用户浏览网站应用的体验
1.3 Ajax 的应用场景
- 页面上拉加载更多数据
- 列表数据无刷新分页
- 表单项离开焦点数据验证
- 搜索框提示文字下拉列表
1.4 Ajax 的运行环境
Ajax 技术需要运行在网站环境中才能生效,当前课程会使用Node创建的服务器作为网站服务器
2. Ajax 运行原理及实现
2.1 Ajax 运行原理
Ajax 相当于浏览器发送请求与接收响应的代理人,以实现在不影响用户浏览页面的情况下,局部更新页面数据,从而提高用户体验
2.2 Ajax 的实现步骤
//1. 创建 Ajax 对象
var xhr = new XMLHttpRequest();
//2. 告诉 Ajax 请求后端的地址以及请求方式
xhr.open('get', 'http://www.example.com');
//3. 发送请求
xhr.send();
//4. 获取服务器端给与客户端的响应数据
xhr.onload = function () {
console.log(xhr.responseText);
}
2.3 服务器端响应的数据格式
在真实的项目中,服务器端大多数情况下会以 JSON 对象作为响应数据的格式。当客户端拿到响应数据时,会被转换为对象字符串,所以要将 对象字符串转换为JSON 数据,再和 HTML 字符串进行拼接,然后将拼接的结果展示在页面中
注意:在 http 请求与响应的过程中,无论是请求参数还是响应内容,如果是对象类型,最终都会被转换为对象字符串进行传输
JSON.parse() // 将 json 字符串转换为json对象
JSON.stringify() // 将json对象转换为json字符串
get start
//客户端html文件
<script type="text/javascript">
// 1.创建ajax对象
var xhr = new XMLHttpRequest();
// 2.告诉Ajax对象要向哪发送请求,以什么方式发送请求
// 1)请求方式 2)请求地址
xhr.open('get', 'http://localhost:3000/responseData');
// 3.发送请求
xhr.send();
// 4.获取服务器端响应到客户端的数据
xhr.onload = function (){
// console.log(typeof xhr.responseText)
// 将JSON字符串转换为JSON对象
var responseText = JSON.parse(xhr.responseText);
// 测试:在控制台输出处理结果
console.log(responseText,responseText.name)
}
</script>
// 服务器端app.js
// 引入express框架
const express = require('express');
// 路径处理模块
const path = require('path');
// 创建web服务器
const app = express();
// 静态资源访问服务功能
app.use(express.static(path.join(__dirname, 'public')));
// 返回响应
app.get('/responseData', (req, res) => {
res.send({"name": "zs"});
});
2.4 请求参数传递
传统网站表单提交
<form method="get" action="http://www.example.com">
<input type="text" name="username"/>
<input type="password" name="password">
</form>
<!–- http://www.example.com?username=zhangsan&password=123456 -->
2.4.1 GET 请求方式
xhr.open('get', 'http://www.example.com?name=zhangsan&age=20');
get start
//1. 客户端文件
var xhr = new XMLHttpRequest();
// get方式
var params = 'name=zhangsan&age=20';
xhr.open('get', 'http://www.example.com?'+params);
xhr.send();
// 获取服务器端响应到客户端
xhr.onload = function (){
var responseText = JSON.parse(xhr.responseText);
console.log(responseText);
}
//结果:{name: zhangsan, age: 20}
//2. 服务器端app.js
const express = require('express');
const path = require('path');
// 创建web服务器
const app = express();
// 静态资源访问服务功能
app.use(express.static(path.join(__dirname, 'public')));
// 返回响应
app.get('/get', (req, res) => {
res.send(req.query);
});
2.4.2 POST 请求方式
xhr.open('post', 'http://localhost:3000/post');
//设置报文头(post请求必须要设置)
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
//设置报文体
xhr.send('name=zhangsan&age=20');
请求参数的格式:
-
application/x-www-form-urlencoded
name=zhangsan&age=20&sex=男
-
application/json
{name: 'zhangsan', age: '20', sex: '男'}
在请求头中指定 Content-Type 属性的值是 application/json,告诉服务器端当前请求参数的格式是 json
JSON.stringify() // 将json对象转换为json字符串
注意:get 请求是不能提交 json 对象数据格式的,传统网站的表单提交也是不支持 json 对象数据格式的
get start
- application/x-www-form-urlencoded格式参数 服务端的处理
//1. 客户端文件
var xhr = new XMLHttpRequest();
xhr.open('post', 'http://localhost:3000/post');
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send('name=zhangsan&age=20');
// 获取服务器端响应的数据
xhr.onload = function () {
var responseText = JSON.parse(xhr.responseText);
console.log(responseText);
}
//结果:{name: zhangsan, age: 20}
//2. 服务器端app.js
const express = require('express');
const path = require('path');
const bodyParser = require('body-parser');
//服务端配置具体的格式
app.use(bodyParser.urlencoded());
const app = express();
app.use(express.static(path.join(__dirname, 'public')));
app.post('/post', (req, res) => {
// 需要引入body-parser模块
res.send(req.body);
});
- 客户端application/json 格式参数 服务端的处理
//1.客户端
var xhr = new XMLHttpRequest();
xhr.open('post', 'http://localhost:3000/json');
xhr.setRequestHeader('Content-Type', 'application/json');
// JSON.stringify() 将json对象转换为json字符串
// 3.发送请求 (参数必须为字符串)
xhr.send(JSON.stringify({name: 'lisi', age:50}));
xhr.onload = function (){
console.log(xhr.responseText)
}
//结果:{"name":"lisi","age":50}
//2. 服务器端app.js
const express = require('express');
const path = require('path');
const bodyParser = require('body-parser');
//服务端配置具体的格式
app.use(bodyParser.json());
const app = express();
app.use(express.static(path.join(__dirname, 'public')));
app.post('/post', (req, res) => {
// 需要引入body-parser模块
res.send(req.body);
});
2.5 获取服务器端的响应
2.5.1 Ajax 状态码
在创建ajax对象,配置ajax对象,发送请求,以及接收完服务器端响应数据,这个过程中的每一个步骤都会对应一个数值,这个数值就是ajax状态码
0:请求未初始化(还没有调用open())
1:请求已经建立,但是还没有发送(还没有调用send())
2:请求已经发送
3:请求正在处理中,通常响应中已经有部分数据可以用了
4:响应已经完成,可以获取并使用服务器的响应了
xhr.readyState // 获取Ajax状态码
2.5.2 onreadystatechange 事件
当 Ajax 状态码发生变化时将自动触发该事件
在事件处理函数中可以获取 Ajax 状态码并对其进行判断,当状态码为 4 时就可以通过 xhr.responseText 获取服务器端的响应数据了
// 当Ajax状态码发生变化时
xhr.onreadystatechange = function () {
// 判断当Ajax状态码为4时
if (xhr.readyState == 4) {
// 获取服务器端的响应数据
console.log(xhr.responseText);
}
}
get start
// 1.客户端
var xhr = new XMLHttpRequest();
// 0 已经创建了ajax对象 但是还没有对ajax对象进行配置
console.log(xhr.readyState);
xhr.open('get', 'http://localhost:3000/readystate');
// 1 已经对ajax对象进行配置 但是还没有发送请求
console.log(xhr.readyState);
// 当ajax状态码发生变化的时候出发
xhr.onreadystatechange = function() {
// 2 请求已经发送了
// 3 已经接收到服务器端的部分数据了
// 4 服务器端的响应数据已经接收完成
console.log(xhr.readyState);
// 对ajax状态码进行判断 如果状态码的值为4就代表数据已经接收完成了
if (xhr.readyState == 4) {
console.log(xhr.responseText);
}
}
xhr.send();
//0 1 2 3 4 hello
//2. 服务器端app.js
const express = require('express');
const path = require('path');
const app = express();
app.use(express.static(path.join(__dirname, 'public')));
app.get('/get', (req, res) => {
res.send('hello');
});
2.5.3 获取服务器端的响应
两种获取服务器端响应方式的区别
区别描述 | onload事件 | onreadystatechange事件 |
---|---|---|
是否兼容IE低版本 | 不兼容 | 兼容 |
是否需要判断Ajax状态码 | 不需要 | 需要 |
被调用次数 | 一次 | 多次 |
2.6 Ajax 错误处理
-
网络畅通,服务器端能接收到请求,服务器端返回的结果不是预期结果。
可以判断服务器端返回的状态码,分别进行处理。xhr.status 获取http状态码 -
网络畅通,服务器端没有接收到请求,返回404状态码。
检查请求地址是否错误 -
网络畅通,服务器端能接收到请求,服务器端返回500状态码。
服务器端错误,找后端程序员进行沟通 -
网络中断,请求无法发送到服务器端。
会触发xhr对象下面的onerror事件,在onerror事件处理函数中对错误进行处理
get start
var btn = document.getElementById('btn');
btn.onclick = function () {
// 1.创建ajax对象
var xhr = new XMLHttpRequest();
// 2.告诉Ajax对象要向哪发送请求,以什么方式发送请求
// 1)请求方式 2)请求地址
xhr.open('get', 'http://localhost:3000/error');//请求地址错误404
// 3.发送请求
xhr.send();
// 4.获取服务器端响应到客户端的数据
xhr.onload = function (){
// xhr.status 获取http状态码
console.log(xhr.responseText);
if (xhr.status == 400) {
alert('请求出错')
}
}
// 当网络中断时会触发onerrr事件
xhr.onerror = function () {
alert('网络中断, 无法发送Ajax请求')
}
}
// Ajax状态码: 表示Ajax请求的过程状态 ajax对象返回的
// Http状态码: 表示请求的处理结果 是服务器端返回的
//服务器端
...
app.get('/error', (req, res) => {
//console.log(abc);语法错误500
res.status(400).send('not ok');
});
2.7 低版本 IE 浏览器的缓存问题
问题:在低版本的 IE 浏览器中,Ajax 请求有严重的缓存问题,即在请求地址不发生变化的情况下,只有第一次请求会真正发送到服务器端,后续的请求都会从浏览器的缓存中获取结果。即使服务器端的数据更新了,客户端依然拿到的是缓存中的旧数据
解决方案:在请求地址的后面加请求参数,保证每一次请求的请求参数的值不相同
xhr.open('get', 'http://www.example.com?t=' + Math.random());
get start
var btn = document.getElementById('btn');
btn.onclick = function () {
var xhr = new XMLHttpRequest();
// 请求参数的值不相同
xhr.open('get', 'http://localhost:3000/cache?t=' + Math.random());
xhr.send();
xhr.onreadystatechange = function (){
// 数据已经接收完成并响应正常
if (xhr.readyState == 4 && xhr.status == 200) {
alert(xhr.responseText);
}
}
}
const fs = require('fs');
...
app.get('/cache', (req, res) => {
fs.readFile('./test.txt', (err, result) => {
res.send(result);
});
});
3. Ajax 异步编程
3.1 同步异步概述
3.1.1 同步
上一行代码执行完成后,才能执行下一行代码,即代码逐行执行
3.1.2 异步
异步代码虽然需要花费时间去执行,但程序不会等待异步代码执行完成后再继续执行后续代码,而是直接执行后续代码,当后续代码执行完成后再回头看异步代码是否返回结果,如果已有返回结果,再调用事先准备好的回调函数处理异步代码执行的结果
console.log('before');
setTimeout(
() => { console.log('last');
}, 2000);
console.log('after');
3.2 Ajax 封装
问题:发送一次请求代码过多,发送多次请求代码冗余且重复
解决方案:将请求代码封装到函数中,发请求时调用函数即可
ajax({
type: 'get',
url: 'http://www.example.com',
success: function (data) {
console.log(data);
}
})
请求参数要考虑的问题
1.请求参数位置的问题
将请求参数传递到ajax函数内部, 在函数内部根据请求方式的不同将请求参数放置在不同的位置
- get 放在请求地址的后面
- post 放在send方法中
2.请求参数格式的问题
-
application/x-www-form-urlencoded
参数名称=参数值&参数名称=参数值
name=zhangsan&age=20
- application/json
{name: 'zhangsan', age: 20}
1).传递对象数据类型对于函数的调用者更加友好
2).在函数内部对象数据类型转换为字符串数据类型更加方便
// ajax函数的封装
function ajax(options) {
// 默认参数
var defaults = {
type: 'get',
url: '',
data: {},
header: {
'Content-Type': 'application/x-www-form-urlencoded'
},
success: function () { },
error: function () { }
}
// 使用defaults的属性覆盖options的属性
Object.assign(defaults, options);
// 参数的格式转换
var params = '';
for (var attr in defaults.data) {
params += attr + '=' + defaults.data[attr] + '&';
}
// 最后一个&字符截去
params = params.substr(0, params.length - 1);
console.log(params);
var xhr = new XMLHttpRequest();
// 请求类型不同 参数位置不同
if (defaults.type == 'get') {
xhr.open(defaults.type, defaults.url + '?' + params);
xhr.send();
} else if (defaults.type == 'post') {
// 用户传递的参数类型
var contentType = defaults.header['Content-Type'];
xhr.open(defaults.type, defaults.url);
xhr.setRequestHeader('Content-Type', contentType)
// 请求参数类型不同
if (contentType == 'application/json') {
xhr.send(JSON.stringify(defaults.data));
} else {
xhr.send(params);
}
}
// 响应处理函数
xhr.onload = function () {
// 服务器端的响应类型
var contentType = xhr.getResponseHeader('Content-Type');
// 将返回的对象字符串转换为对象
var responseText = xhr.responseText;
console.log('contentType', contentType);
if (contentType.includes('application/json')) {
responseText = JSON.parse(responseText);
}
if (xhr.status == 200) {
options.success(responseText);
} else {
options.error(responseText);
}
}
}
// 配置ajax函数的参数
ajax({
type: 'get',
url: 'http://localhost:3000/responseData',
data: {
name: 'zhangsan',
age: 18
},
header: {
'Content-Type': 'application/json'
},
success: function (data) {
console.log(data + '获取成功');
},
error: function (data) {
console.log(data + '获取失败');
}
});
//输出:
//name=zhangsan&age=18
//contentType application/json; charset=utf-8
//[object Object]获取成功
...
app.get('/responseData', (req, res) => {
res.send({"name": "zs"});
});
4. FormData
4.1 FormData对象的作用
- 模拟HTML表单,相当于将HTML表单映射成表单对象,自动将表单对象中的数据拼接成请求参数的格式
- 异步上传二进制文件
4.2 FormData对象的使用
<!-- 1.创建表单对象 -->
<form id="form">
<input type="text" name="username">
<input type="password" name="password">
<input type="text" id="btn" value="提交">
</form>
<script>
//2. 获取表单对象
var form = document.getElementById('form');
var btn = document.getElementById('btn');
btn.onclick = function() {
// 3.将 HTML 表单转化为 formData 对象
var param = new FormData(form);
var xhr = new XMLHttpRequest();
xhr.open('post', 'http://localhost:3000/formData');
// 4.提交表单对象 到服务器端(post)
xhr.send(param);
}
// 5.监听xhr对象下面的onload,接收响应数据
xhr.onload = function() {
if(xhr.status == 200) {
// 响应正常
console.log(xhr.responseText);
}
}
// 6.异常处理
xhr.onerror = function() {
console.log("响应异常");
}
</script>
- 注意:
- Formdata 对象不能用于 get 请求,因为对象需要被传递到 send 方法中,而 get 请求方式的请求参数只能放在请求地址的后面。
- 服务器端 bodyParser 模块不能解析 formData 对象表单数据,我们需要使用 formidable 模块进行解析。
4.2 formidable模块
- 之前一直使用body-parse模块对客户端post传递的参数进行解析
- 但是body-parse模块不能对FormData进行解析
- 需要下载和使用另一个模块formidable
// 服务器端app.js
const formidable = require('formidable');
// 创建网站服务器...引入http模块
...
// 处理formData路由请求
app.post('/formData', (res, req) => {
// 创建formidable表单解析对象
const form = new formidable.IncomingForm();
// 解析客户端传过来的FormData对象 参数:错误对象 普通参数组成的对象 上传文件
form.parse(req, (err, fields, files) => {
res.send(fields);
})
});
// 监听端口
app.listen(3000);
console.log("服务器响应成功");
4.3 实例方法
// 1.获取表单对象的属性的值
formData.get('key');
// 2.设置表单对象属性的值
formData.set('key', 'value');
// 注意:如果设置的key不存在,将会创建这个表单属性
// 注意:如果设置的key存在,将会改变这个表单属性的值
// 3.删除表单对象的属性
formData.delete('key');
// 4.向表单对象追加一个
formData.append('key', 'value');
var f = new FormData();//创建空的表单对象
f.append('sex','nan');
console.log(f.get('sex'));
- 注意:set和append方法的区别:当属性存在时,set会改变属性的值,而append会保留2个属性及其值,但是服务器只会接收属性最后传递的值
4.4 FormData二进制文件上传
- get请求方式不能用于文件上传
<input type="file" id="file">
<script>
var file = document.getElementById('file');
// 当用户选择文件的时候
file.onchange = function(){
var formData = new FormData();
// 将用户选择的二进制文件追加到表单对象中
formData.append('attrName', this.files[0]);
// 创建ajax对象
var xhr = new XMLHttpRequest();
// 初始化ajax对象,请求方式必须为post
xhr.open('post', 'http://localhost:3000/upload');
xhr.send(formData);
// 监听响应数据
xhr.onload = function() {
if(xhr.status == 200) {
// 请求成功 响应正常
console.log(xhr.responseText);
}
}
}
</script>
// 服务器端
app.post('/upload', (req, res) => {
// 创建解析对象
const form = new formidable.IncomingForm();
// 设置客户端上传文件的存储路径 __dirname找到当前目录,拼接后面的路径
form.uploadDir = path.join(__dirname, 'public','uploads');
// 保存文件后缀
form.keepExtensions = true;
// 解析客户端请求参数
form.parse(req, (err, fields, files) => {
res.send("ok");
});
})
文件上传进度展示
<div class = "progress">
<div class = "progress-bar" id="bar" style="width:60%">60%</div>
</div>
var bar = document.getElementById('bar');
file.change = function() {
// xhr的upload保存了文件上传的相关信息
// 在文件上传过程 会持续触发onprogress事件(参数:事件对象)
xhr.upload.onprogress = function(event) {
// 文件上传了多少loaded
// 文件总大小total
var result = (event.loaded / event/total) * 100 + '%';
// 将结果赋值给进度条的宽度属性
bar.style.width = result;
bar.innerHTML = result;
}
}
上传图片即时预览
- 在服务器端中,将客户端上传的图片地址响应到客户端,显示出来
- 由于图片是静态资源,可以直接访问,需要spilt分割路径
form.parse(req, (err, fields, files) => {
// attrName是客户端传过来的FormData对象的属性名
res.send({
path: files.attrName.path.split('public')[1]
});
// 此时得到的是/uploads/...jpg
})
<div id="box"></div>
<script>
var box = document.getElementById('box');
xhr.onload = function() {
if(xhr.status == 200) {
var result = JSON.parse(xhr.responseText);
// 动态创建img元素,不想让用户看到图片加载的过程
var img = document.createElement('img');
img.src = result.path;
// 当图片加载完之后,显示到页面中
// img上有onload事件 加载图片完触发
img.onload = function() {
box.appendChild(img);
}
}
}
</script>
5. Ajax请求限制-同源政策
5.1 Ajax请求限制
- Ajax只能向自己的服务器发送请求
- 不能向其他网站的服务器发送请求
什么是同源?
- 多个请求/页面是否来自同一个服务器端
- 判断的标准:三个都相同(协议 域名 端口),否则不同源
- 不写端口,默认80
同源政策的目的
- 同源政策是为了保护用户的信息安全,防止恶意的网站窃取数据
- 最初的同源政策是指A网站在客户端设置的Cookie,B网站不能访问
- 非同源的网站之间是不能发送ajax请求的
- 如果发送了,请求是可以发送出去的,只不过浏览器拒绝接收服务器端的响应,所以请求报错
5.2 解决同源限制问题-使用JSONP
jsonp是json with padding的缩写,可以模拟ajax请求,但不是ajax请求
原理:利用script标签可以向非同源的服务器端发送请求的特性, 在服务端中返回函数调用的代码,(虽然服务端返回的是字符串,但因为写在客户端script中,会被当做js执行)当客户端加载完响应内容以后,这段响应内容会被当做js来执行,函数就被调用了,此时客户端已经提前准备好了函数的定义,通过函数的参数就可以获取接收的数据
(1)不同源的服务器端请求地址写在script标签的src属性中
<script src="www.example.com"></script>
<script src=“https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
(2)服务端返回的是函数调用语句的字符串,(不是字符串就会直接在服务端执行,而实际我们想在客户端执行),同时发送给客户端的数据作为函数调用的参数传递
const data = 'fn({name: "张三", age: "20"})';
res.send(data);
(3)在客户端全局下定义好函数fn(以便返回的函数调用语句执行时不会说函数不存在)
function fn (data) { }
(4)在 fn 函数内部对服务器端返回的数据进行处理
function fn (data) { console.log(data); }
例子:
<!-- 1号网站http://localhost:3000 客户端 -->
<script>
function fn(data) {
console.log('客户端的fn被调用了');
console.log(data);
}
</script>
<!-- 在下面服务器地址加载完毕后 会调用上面的函数 -->
<script src="http://localhost:3001/test"></script>
// 2号网站http://localhost:3001 服务端
app.get('test', (req, res) => {
const result = 'fn({name: "ccc"})';
res.send(result);
})
JSON代码优化
- script在html页面中会自动加载,需要将script请求的发送变为动态请求
- 客户端需要将函数的名称传递到服务器端
- 封装jsonp函数,方便请求发送
- 服务器端代码优化之 res.jsonp 方法
<button id='btn'></button>
var btn = document.createElement('script');
script.src = 'http://localhost:3001/test';
document.body.appendChild(script);
// script标签加载完时触发
script.onload = function () {
// 加载完 script标签就没有意义了
document.body.removeChild(script);
}
- 客户端将更新后的函数的名称传递到服务器端,需要在请求地址后,通过get方式添加callback参数,参数的值就是函数名称
script.src = 'http://localhost:3001/test?callback=fn';
// 2号网站http://localhost:3001 服务端
app.get('test', (req, res) => {
const fnName = req.query.callback;
// 将函数名称对应的函数调用代码返回客户端
const result = fnName + '({name: "ccc"})';
res.send(result);
// 服务端以上代码优化 等价于下面一句
// res.jsonp({name:"ccc"});
})
- 封装jsonp函数,参数为对象,包含请求地址url属性(添加callback参数)
综合上面代码进行封装:
1.动态创建script标签,添加src属性为url
2.绑定加载事件onload,删除加载完无意义的当前script
完整的代码优化过程
-
btn点击事件中,调用jsonp({url})函数
-
服务端中获取req.query.callback函数名称
-
在返回函数调用代码中,添加函数名
-
函数定义添加到jsonp对象参数中
-
get请求参数添加到jsonp对象参数中
5.3 CORS 跨域资源共享
CORS:全称为 Cross-origin resource sharing,即跨域资源共享,它允许浏览器向跨域服务器发送 Ajax 请求,克服了 Ajax 只能同源使用的限制
浏览器向服务端发送请求,请求头 (origin)
服务端向客户端返回响应,响应头(Access-Control-Access-Origin)
-
Node 服务器端设置响应头示例代码:
app.use((req, res, next) => { res.header('Access-Control-Allow-Origin', '*'); res.header('Access-Control-Allow-Methods', 'GET, POST'); next(); })
5.4 同源政策-服务端解决方案
服务端不存在同源政策
- 使用到第三方模块request
- 客户端先向自身的服务端发送请求
- 用自身的服务器端利用request(url, (err, res, body) = {})向其他服务器端发送请求
6. withCredentials属性
- http协议的无状态:客户端和服务器端之间的请求和响应遵循http协议的无状态,也就是谁也不认识谁,只要有请求发送,服务端就响应,但服务端并不知道客户端已经来过一次
- cookie:客户端第一次访问服务器端时,服务器端会向客户端发送一个响应cookie,这是服务端对客户端的唯一识别,有利于服务端和客户端之间的持久连接。当客户端再次发送请求时,cookie会随着请求发送到服务端,用于识别身份
- 但是,在使用ajax发送跨域请求时,默认不会在请求中携带cookie信息
- 如果想要在跨域请求中携带cookie,需要在服务器端和客户端都设置Credentials
// 1.在网站1客户端中设置
// 当发送跨域请求时,携带cookie信息
xhr.wiithCredentials = true;
xhr.send(formData);
withCredentials:指定在涉及到跨域请求时,是否携带cookie信息,默认值为false
Access-Control-Allow-Credentials:true 允许客户端发送请求时携带cookie
// 2.在网站2服务端中设置
// 允许客户端发送跨域请求时携带cookie信息
res.header('Access-Control-Allow-Credentials', true);
// 注意:如果跨域请求中涉及到cookie信息传递,值不可以为*号 比如是具体的域名信息
res.header('Access-Control-Allow-Origin', 'http://localhost:3000')
// 2.允许客户端使用哪些请求方法访问我
res.header('Access-Control-Allow-Methods', 'get,post')
7. $.ajax()
7.1 $.ajax()方法概述
7.1.1 作用:发送Ajax请求
$.ajax({
type: 'get',
url: 'http://www.example.com',
data: { name: 'zhangsan', age: '20' },
contentType: 'application/x-www-form-urlencoded',
beforeSend: function () {
return false
},
success: function (response) {},
error: function (xhr) {}
});
{
data: 'name=zhangsan&age=20'
}
{
contentType: 'application/json'
}
JSON.stringify({name: 'zhangsan', age: '20'})
7.1.2 作用:发送jsonp请求
$.ajax({
url: 'http://www.example.com',
// 指定当前发送jsonp请求
dataType: 'jsonp',
// 修改callback参数名称,默认叫callback
jsonp: 'cb',
// 指定函数名称
jsonCallback: 'fnName',
success: function (response) {}
})
7.2 serialize方法
作用:将表单中的数据自动拼接成字符串类型的参数
var params = $('#form').serialize();
// name=zhangsan&age=30
7.3 .post()
作用:.post方法用于发送post请求
$.get('http://www.example.com', {name: 'zhangsan', age: 30}, function (response) {})
$.post('http://www.example.com', {name: 'lisi', age: 22}, function (response) {})
三个参数:请求地址,请求参数,请求成功时回调函数(请求参数可省略)
8. jQuery中Ajax全局事件
8.1 全局事件
只要页面中有Ajax请求被发送,对应的全局事件就会被触发
全局事件必须被绑定在document元素上
.ajaxStart() // 当请求开始发送时触发
.ajaxComplete() // 当请求完成时触发
$(document).on('ajaxStart', function() {})
8.2 NProgress
官宣:纳米级进度条,使用逼真的涓流动画来告诉用户正在发生的事情!
<link rel='stylesheet' href='nprogress.css'/>
<script src='nprogress.js'></script>
NProgress.start(); // 进度条开始运动
NProgress.done(); // 进度条结束运动
$(document).on('ajaxStart', function() {
NProgress.start();
})
9. RESTful 风格的 API
9.1 传统请求地址
GET http://www.example.com/getUsers // 获取用户列表
GET http://www.example.com/getUser?id=1 // 比如获取某一个用户的信息
POST http://www.example.com/modifyUser // 修改用户信息
GET http://www.example.com/deleteUser?id=1 // 删除用户信息
9.2 RESTful API 概述
一套关于设计请求的规范
GET: 获取数据
POST: 添加数据
PUT: 更新数据
DELETE: 删除数据
请求数据 => 请求地址
users => /users
articles => /articles
RESTful API 的实现:
GET:http://www.example.com/users 获取用户列表数据
POST:http://www.example.com/users 创建(添加)用户数据
GET:http://www.example.com/users/1 获取用户ID为1的用户信息
PUT:http://www.example.com/users/1 修改用户ID为1的用户信息
DELETE:http://www.example.com/users/1 删除用户ID为1的用户信息
// 服务器端
app.put('/users/:id', (req, res) => {
const id = req.params.id;
res.send(`当前我们在修改id为${id}的用户信息`);
})
//客户端
$.ajax({
type: 'put',
url: '/users/10',
success: function(response) {
console.log(response);
}
})
10. XML
XML 的全称是 extensible markup language,代表可扩展标记语言,它的作用是传输和存储数据
<students>
<student>
<sid>001</sid>
<name>张三</name>
</student>
<student>
<sid>002</sid>
<name>王二丫</name>
</student>
</students>
XML DOM
XML DOM 即 XML 文档对象模型,是 w3c 组织定义的一套操作 XML 文档对象的API。浏览器会将 XML 文档解析成文档对象模型
//客户端
xhr.onload = function () {
// xhr.responseXML 获取服务器端返回的xml数据
var xmlDocument = xhr.responseXML;
var title = xmlDocument.getElementsByTagName('title')[0].innerHTML;
container.innerHTML = title;
}
// 服务器端
app.get('/xml', (req, res) => {
res.header('content-type', 'text/xml');
res.send('<message><title>消息标题</title><content>消息内容</content></message>')
});
网友评论