FormData对象和同源政策,跨域问题的解决
6 FormData对象
- FormData对象可以上传普通数据和二进制文件
- 相对于普通的数据表单的特点
- 通过内置对象FormData可以自动拼接发送给服务器端的参数,不需要在手动进行拼接
- 避免一个一个的通过dom操作获取所有的提交控件按钮对象和值,
- 不需要为表单添加提交地址和提交方式,会通过ajax技术向服务器端提供
- 不需要submit提交按钮直接向服务器端发送请求,但一定要写name属性
- 只能用于post请求方式,且是将form对象放在send()方法中发送非服务器
- 作用
- 模拟HTML表单,相当于将HTML表单映射成表单对象,自动将表单对象中的数据拼接成请求参数的格式。
- 异步上传二进制文件
- 注意:
- 实现
- 客户端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17var btn = document.querySelector("#btn");
console.log(btn)
// 为按钮设置点击事件
btn.onclick = function () {
// 获取form对象
var form = document.querySelector('#form');
// 将表单转化为form对象
var formData = new FormData(form);
// 创建ajax对象实例提交表单信息
var xhr = new XMLHttpRequest();
xhr.open('post', 'http://localhost:3000/formData');
xhr.send(formData);
xhr.onload = function () {
console.log(xhr.responseText)
}
}
</script> - 服务器端(先下载第三方模块formidable)
1
2
3
4
5
6
7
8app.post('/formData', (req, res) => {
// 创建formidable表单解析对象
const form = new formidable.IncomingForm()
// 解析客户端传递过来的FormData对象
form.parse(req, (err, fields, files) => {
res.send(fields);
});
});
- 客户端
- 执行结果
6.2 FormData的实例方法
- 注意FormData中的字段必须要有name属性才能用于表单的提交等
- formdata的实例方法,这里的key是name属性名
- 1.get(‘key’)
- 2.set(“key”,value)
- key存在的情况下会覆盖原先的内容 - key不存在的情况下会重新创建一个属性
- 3.append(“key”,value)
- 4.delete(‘key’)
- 代码:
1
2
3
4
5
6
7var username = formData.get('username')
console.log(username);
formData.set('username', '李四');
formData.set('age', 12);
formData.append("age", 14);
console.log(formData.get('username'))
formData.delete("age");//删除最后一个age - 执行结果
- set()和append()方法的区别
- 二者都可以向formdata对象中添加属性
- set()设置不存在的属性时等价于append(),设置存在的会直接覆盖原先的值
- append()添加存在属性存不会直接覆盖,会保留原先的值重新建一个新的值
- 服务器端接受相同的属性只会返回最后一个
- FormData对象使用见链接
- FormData实例方法
6.3 FormData二进制文件上传
- 二进制文件:图片视频音频
- 知识点
- 选择文件触发onchange事件
- 通过file对象.files返回上传文件的文数组(设置multiple属性时为多个文件列表)
- 通过formidable第三方模块处理客户端传递过来的参数
- 实现进度条功能
- xhr.upload:XMLHttpRequest.upload 属性返回一个 XMLHttpRequestUpload对象,用来表示上传的进度。这个对象是不透明的,但是作为一个XMLHttpRequestEventTarget,可以通过对其绑定事件来追踪它的进度。被绑定在upload对象上的事件监听器如下:链接
- onloadstart 获取开始
- onprogress 数据传输进行中
- onabort 获取操作终止
- onerror 获取失败
- onload 获取成功
- ontimeout 获取操作在用户规定的时间内未完成
- onloadend 获取完成(不论成功与否)
- xhr.upload.onprocess在文件上传的过程中持续触发的进度条事件
- ev.loaded 文件已经上传了多少(ev是事件对象)
- ev.total 上传文件的总大小
- xhr.upload:XMLHttpRequest.upload 属性返回一个 XMLHttpRequestUpload对象,用来表示上传的进度。这个对象是不透明的,但是作为一个XMLHttpRequestEventTarget,可以通过对其绑定事件来追踪它的进度。被绑定在upload对象上的事件监听器如下:链接
- 在图片加载完成以后自动调用的方法是onload事件
1
2
3
4// 图片加载完成之后显示在页面中
img.onload = function () {
box.appendChild(img);
} - FormData 文件上传图片即时预览
- 在我们将图片上传到服务器端以后,服务器端通常都会将图片地址做为响应数据传递到客户端,客户端可以从响应数据中获取图片地址,然后将图片再显示在页面中。
1
2
3
4
5
6
7
8
9xhr.onload = function () {
var result = JSON.parse(xhr.responseText);
var img = document.createElement('img');
img.src = result.src;
<!--图片上传结束之后将图片显示在当前页面 -->
img.onload = function () {
document.body.appendChild(this);
}
} - 文件上传预览还可以通过内置对象FileReader,文件读取结束之后,调用onload监听事件设置img的src属性
- 缺陷:只能在支持HTML5的浏览器中使用
- 在我们将图片上传到服务器端以后,服务器端通常都会将图片地址做为响应数据传递到客户端,客户端可以从响应数据中获取图片地址,然后将图片再显示在页面中。
- 实现
- 客户端
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
55
56
57
58
59
60
61
62
63
64<div class="container">
<div class="form-group">
<label>请选择文件</label>
<input type="file" id="file">
<div class="padding" id="box">
<!--<img src="" class="img-rounded img-responsive">-->
</div>
<div class="progress">
<div class="progress-bar" style="width: 0%;" id="bar">0%</div>
</div>
</div>
</div>
<script>
// 获取上传的文件对象
var file = document.querySelector('#file');
// 获取进度条元素
var bar = document.querySelector('#bar');
// 获取图片容器
var box = document.querySelector('#box');
// 为文件选择时触发onchange事件
file.onchange = function () {
// 创建空的的formData对象存储文件
var formData = new FormData();
// 向formData中添加对象
formData.append('attrName', this.files[0]);
// 创建ajax对象
var xhr = new XMLHttpRequest();
// 配置,注意这里只能使用post请求方式
xhr.open('post', 'http://localhost:3000/uploads');
// 在文件上传的过程中持续触发(文件上传对象)
xhr.upload.onprogress = function (event) {
// ev.loaded 文件已经上传了多少
// ev.total 上传文件的总大小
var result = (event.loaded / event.total) * 100 + '%';
// 设置进度条的宽度
bar.style.width = result;
bar.innerHTML = result;
console.log(result)
console.log(event);
}
// 发送请求
xhr.send(formData);
// 监听服务器端响应给客户端的数据
xhr.onload = function () {
// 返回正确的值
if (xhr.status == 200) {
// 将结果显示在客户端
console.log(xhr.responseText)
var result = JSON.parse(xhr.responseText);
// 动态创建img标签
var img = document.createElement('img');
// 设置图片标签设置src属性
img.src = result.path;
// 图片加载完成之后显示在页面中
img.onload = function () {
box.appendChild(img);
}
}
}
} - 服务器端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16// 实现文件上传的路由
app.post('/uploads', (req, res) => {
// 创建formidable表单解析对象
const form = new formidable.IncomingForm();
// 设置客户端上传文件的存储路径
form.uploadDir = path.join(__dirname, 'public', 'uploads');
// 保留上传文件的后缀名字
form.keepExtensions = true;
// 解析客户端传递过来的FormData对象
form.parse(req, (err, fields, files) => {
// 将客户端传递过来的文件地址响应到客户端
res.send({
path: files.attrName.path.split('public')[1]
});
});
});7 同源政策
7.1 ajax请求的限制
- 客户端
- ajax请求只能向自己的服务器发送请求
7.2 同源
- 如果两个页面拥有相同的协议,相同的域名,相同的端口,这两个页面就是同源的(属于向同一个服务器发送请求),只要有一个不同就是不同源
7.3 同源策略的目的
- 同源政策是为了保证用户信息的安全,防止恶意的网站窃取数据
- 最初的同源政策是指A网站在客户端设置的cookie,B网站是不能访问的
- 不同源的情况下,其中有一项规定就是无法向非同源地址发送Ajax 请求,如果请求,浏览器就会报错。(注意这里的请求是发送出去的但是浏览器端拒绝接受,所有也是失败的)
7.4 JSONP 解决同源限制问题
- 这里需要设置两个不同端口的服务器分别开启进行测试实验
- 不同源的网站中是不允许发送ajax请求的,但是在现实需求中是需要向不同的网站中发送ajax请求
- JSONP 的解决方案实质:绕过同源政策的限制向非同源服务器发送请求
- JSONP发送的请求是get请求,它是通过src的方式发送给服务器端的
JSONP实现
JSONP实现:json with padding,它不属于ajax请求,但是可以模拟ajax请求,这种解决方案需要前后端人员配合完成.执行步骤如下:
- 1.将不同源的服务器地址写在script标签的src属性中
- 注意:并不是所有的请求都是遵循同源政策的,script标签scr就是绕过同源政策发送请求的,前提是引入之后返回的文件符合js规范的
1
2<script src="www.example.com"></script>
<script src=“https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
- 注意:并不是所有的请求都是遵循同源政策的,script标签scr就是绕过同源政策发送请求的,前提是引入之后返回的文件符合js规范的
- 2.服务器端响应数据必须是一个函数的调用,真正要发送给客户端的数据需要作为函数调用的参数。
- 在服务器端将函数的调用放在字符串中,传递的参数写在函数调用的参数中,函数真正调用时返回在客户端中加载完成直接调用的
- 函数的定义在客户端,在客户端通过传递形参的方式获取服务器端传递过来的参数
1
2
3服务器端
const data = 'fn({name: "张三", age: "20"})';
res.send(data);
- 3.在客户端全局作用域下定义函数 fn,必须放在script引入标签的前面,在数据加载完成之后就会直接调用fn函数
1
2//data形参用来接收服务器端传过来的参数
function fn (data) { } - 4.在 fn 函数内部对服务器端返回的数据进行处理
1
function fn (data) { console.log(data); }
- 完整实现
- 同时开启是是s1 3000端口和s2 3001端口的服务器
- s1客户端代码
1
2
3
4
5
6
7
8
9<script>
// 客户端定义执行函数,且放在script标签的前面
function fn(data) {
// 形参data用于接收从服务器端传过来的实参
console.log(data);
}
</script>
<!-- 1.将非同源服务器端的请求地址写在script标签的src属性中 ,这里的文件加载结束返回的函数就会在立即执行-->
<script src="http://localhost:3001/test"></script> - s2 服务器端代码
1
2
3
4
5
6// 02 使用jsonp向非同源的的服务器发送数据
app.get('/test', (req, res) => {
// 服务器中响应的数据是函数的调用,真正要发送给客户端的数据放在参数中,这里需要将调用的函数放在字符串中,真正的执行是在客户端执行
const result = 'fn({name: "张三"})';
res.send(result);
}); - 执行结果(可以看到s1的请求返回了s2服务器端的数据,解决了同源限制问题)
JSONP优化1
- 优化
- 客户端需要将函数名称传递到服务器端。(这里统一将函数的名称作为参数传递给服务器端callback=函数名称,不必为前后端函数名称不同而进行沟通)
- 将script 请求的发送变成动态请求。(通过点击按钮的方式可以随时实现发送请求)
- 操作
- 通过按钮设置点击事件
- 点击事件触发之后新建script标签
- 当script加载完成之后删除script标签,即在请求发送接收完成之后就删除添加的script标签(dom对象监听加载完成事件用 onload事件),这样就不会在页面中重复增加很多script标签
- 注意:这里虽然也在局部向服务器发送请求,但不是ajax请求,是模拟ajax请求
- 实现
- s1客户端
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<button id="button">点击我发送请求</button>
<script>
// 客户端定义执行函数,且放在script标签的前面
function fn2(data) {
// 形参data用于接收从服务器端传过来的实参
console.log(data);
console.log('客户端程序被执行了')
}
</script>
<script>
// 获取button元素
var btn = document.querySelector('#button');
// 为button设置点击事件
btn.onclick = function () {
// 创建script标签
var script = document.createElement('script');
// 设置src
script.src = 'http://localhost:3001/better?callback=fn2';
// 将script标签添加到页面
document.body.appendChild(script);
// 事件加载完成(onload)之后清除
script.onload = function () {
document.body.remove(script);
}
}
</script> - s2服务器端
1
2
3
4
5
6
7
8
9
10
11app.get('/better', (req, res) => {
// 接收客户端传递过来的函数的名称
const fnName = req.query.callback;
// 将函数名称对应的函数调用代码返回给客户端
const data = JSON.stringify({ name: "张三" });
const result = fnName + '(' + data + ')';
setTimeout(() => {
res.send(result);
}, 1000)
// res.jsonp({ name: 'lisi', age: 20 });
});JSONP优化2-jsonp函数封装
- s1客户端
- 优化
- 封装 jsonp 函数,方便请求发送.封装过程中解决的问题
- 函数的声明放在了封装的函数内部,并通过为window添加属性的方式将局部函数变为全局函数(通过变量添加的属性名需要通过[]添加属性方法)
- 在函数内部随机生成了函数的名称,解决了多次触发请求后面函数覆盖前面函数的问题,注意:这里需要先将数字转化为字符串toString(),再将字符春中的点替换为空replace(),前面必须加字母等,符合js命名的要求
- jsonp为get请求方式,对于传递的参数通过拼接的方式进行发送
- 服务器端代码优化之 res.jsonp 方法
- 封装 jsonp 函数,方便请求发送.封装过程中解决的问题
- 实现
- s1客户端代码
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<script>
var btn = document.querySelector('#button');
btn.onclick = function () {
// 调用jsonp函数
jsonp({
url: 'http://localhost:3001/better',
// 传递的参数
data: {
name: 'lisi',
age: 12
},
// 函数的声明
success: function (data) {
console.log(data);
console.log('客户端的代码被执行');
}
})
}
// 封装jsonp函数
function jsonp(options) {
// 新建script标签
var script = document.createElement('script');
// 拼接字符串的变量
var params = '';
for (var attr in options.data) {
params += '&' + attr + '=' + options.data[attr];
}
// 获取随机的函数名称,避免后面的请求中相同的函数名称覆盖内容,这里需要先将数字转化为字符串在将字符串中的点替换为空
var fnName = 'jsonp' + Math.random().toString().replace('.', '');
// 添加函数的声明(这里是为变量添加属性采用[])函数的声明必须为全局函数这里通过window全局对象进行添加.
window[fnName] = options.success;
// 添加跳转地址
script.src = options.url + '?callback=' + fnName + params;
// 将script添加到html
document.body.appendChild(script);
// script请求发送之后清除scipt标签.请求已经发送结束
script.onload = function () {
document.body.removeChild(script);
}
}
</script> - s2服务器端
1
2
3app.get('/better', (req, res) => {
// 服务器端的优化,上面的所有操作jsonp方法已经全部实现,直接在参数中传入对象
res.jsonp({ name: 'lisi', age: 20 });});7.5 jsonp实现向腾讯天气服务器请求数据
- s1客户端代码
- 知识点
- 向模板引擎中传入外部定义的方法对日期的格式进行设置
1
template.defaults.imports.dataFormat = dataFormat;
- 向模板引擎中传入外部定义的方法对日期的格式进行设置
- 代码实现
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
55
56
57
58
59
60
61<div class="container">
<table class="table table-striped table-hover" align="center" id="box">
</table>
</div>
<script src="/js/jsonp.js"></script>
<script src="/js/template-web.js"></script>
<script type="text/html" id="tpl">
<tr>
<th>时间</th>
<th>温度</th>
<th>天气</th>
<th>风向</th>
<th>风力</th>
</tr>
{{each info}}
<tr>
<td>{{dataFormat($value.update_time)}}</td>
<td>{{$value.degree}}</td>
<td>{{$value.weather}}</td>
<td>{{$value.wind_direction}}</td>
<td>{{$value.wind_power}}</td>
</tr>
{{/each}}
</script>
<script type="text/javascript">
// 获取box
var box = document.querySelector('#box');
// 返回的时间是一个字符串类型,这里通过函数将字符串类型的时间转化为年月日的格式显示(通过字符串的截取实现)
function dataFormat(date) {
var year = date.substr(0, 4);
var month = date.substr(4, 2);
var day = date.substr(6, 2);
var hour = date.substr(8, 2);
var minute = date.substr(10, 2);
var seconds = date.substr(12, 2);
return year + '年' + month + '月' + day + '日' + hour + '时' + minute + '分' + seconds + '秒';
}
// 时间格式,通过向模板中传入外部函数
template.defaults.imports.dataFormat = dataFormat;
//获取腾讯天气信息
jsonp({
url: 'https://wis.qq.com/weather/common',
data: {
source: 'pc',
weather_type: 'forecast_1h',
// 传递多个参数
// weather_type: 'forecast_1h|forecast_24h',
province: '黑龙江省',
city: '哈尔滨市'
},
success: function (data) {
var html = template('tpl', {
info: data.data.forecast_1h
});
//添加模板到html页面中
box.innerHTML = html;
}
})
</script>7.6 CORS跨域资源共享(非同源资源共享)
- CORS:全称为 Cross-origin resource sharing,即跨域资源共享,它允许浏览器向跨域服务器发送 Ajax 请求,克服了 Ajax 只能同源使用的限制。
- 访问过程
- 客户端跨域向非同源服务器端发送ajax请求时会自动在请求头中添加origin字段,字段中存放的是客户端的url,如果不是跨域访问请求头中不会存放origin字段
1
origin: http://localhost:3000
- 非同源服务器端接收到客户端请求之后,在服务器端拦截所有请求,设置是否允许非同源客户端访问
1
2
3Access-Control-Allow-Origin: 'http://localhost:3000'
* 表示允许所有非同源客户端访问
Access-Control-Allow-Origin: '*' - Node 服务器端设置响应头示例代码:
1
2
3
4
5app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET, POST');
next();
}) - 这里只设置服务器端,客户端不用
- 客户端跨域向非同源服务器端发送ajax请求时会自动在请求头中添加origin字段,字段中存放的是客户端的url,如果不是跨域访问请求头中不会存放origin字段
- 跨域访问受限如图
- 代码实现
- 同源政策是浏览器给予Ajax技术的限制,服务器端是不存在同源政策限制。
- 服务器端的解决方案实质:绕过了同源政策的限制,客户端发送ajax请求给自己的服务器,服务器在跨域发送请求给非同源的服务器获取数据,然后在响应给自己的客户端.(服务器端是不存在同源政策限制)
7.7.1 服务器端获取非同源服务器端数据引入expres框架第三方模块request
- 安装
1
npm installrequrest
- 使用
1
2
3
4
5
6request(参数1,参数2)
- 参数1:发送给非同源网站的url
- 参数2:回调函数(err, response, body) =>{}
- err:错误信息
- response:服务器端的响应信息
- body:服务器端响应的主体返回的内容7.7.2服务器解决方案代码实现
- 客户端
- 向自己的服务器发送请求
1
2
3
4
5
6
7
8
9
10
11
12var btn = document.getElementById('btn');
// 为按钮添加点击事件
btn.onclick = function () {
ajax({
type: 'get',
// 向自己的服务器端发送请求
url: 'http://localhost:3000/server',
success: function (data) {
console.log(data)
}
})
};
- 向自己的服务器发送请求
- s1服务器(个人服务器)
- 向s2服务器发送请求
1
2
3
4
5
6
7
8
9
10// 向其他服务器端请求数据的模块
const request = require('request');
app.get('/server', (req, res) => {
request('http://localhost:3001/cross', (err, response, body) => {
console.log(err);
console.log(response);
// console.log(body);
res.send(body);
})
});
- 向s2服务器发送请求
- s2服务器
1
2
3
4
5app.get('/cross', (req, res) => {
res.header('Access-Control-Allow-Origin', 'http://localhost:3000')
res.header('Access-Control-Allow-Methods', 'get,post')
res.send('ok')
});7.7.3跨域请求中携带cookie的问题
- 客户端
- cookie就是实现客户端和服务器端身份识别的一种技术
- cookie信息在发送过程中会随着请求发送给服务器端
withCredentials属性
- 在使用Ajax技术发送跨域请求时,默认情况下不会在请求中携带cookie信息。
- withCredentials:指定在涉及到跨域请求时,是否携带cookie信息,默认值为false
- 实现跨域请求携带cookie必须在客户端和服务器端都要进行设置
- 客户端
1
xhr.withCredentials = true;客户端设置允许发送cookie信息
- 服务器端
1
res.header('Access-Control-Allow-Credentials', true);
- 客户端
- 完整代码实现
- 客户端
- 设置xhr.withCredentials = true;
- 通过FormData对象发送请求参数
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
55
56<div class="container">
<form id="loginForm">
<div class="form-group">
<label>用户名</label>
<input type="text" name="username" class="form-control" placeholder="请输入用户名">
</div>
<div class="form-group">
<label>密码</label>
<input type="password" name="password" class="form-control" placeholder="请输入用密码">
</div>
<input type="button" class="btn btn-default" value="登录" id="loginBtn">
<input type="button" class="btn btn-default" value="检测用户登录状态" id="checkLogin">
</form>
</div>
<script>
// 获取登录按钮
var loginBtn = document.querySelector('#loginBtn');
// 获取检测登录状态的按钮
var checkLogin = document.querySelector('#checkLogin');
// 获取form表单
var form = document.querySelector('#loginForm');
// 添加点击事件
loginBtn.onclick = function () {
// 将html表单转化为FormData表单对象
var formData = new FormData(form);
// 创建ajax对象
var xhr = new XMLHttpRequest();
// 设置发送请求的方式和地址
xhr.open('post', 'http://localhost:3001/login');
// 当发送跨域请求时,携带cookie信息
xhr.withCredentials = true;
// 发送请求
xhr.send(formData);
// 监听服务器端响应
xhr.onload = function () {
console.log(xhr.responseText);
}
checkLogin.onclick = function () {
// 创建ajax对象
var xhr = new XMLHttpRequest();
// 对ajax对象进行配置
xhr.open('get', 'http://localhost:3001/checkLogin');
// 当发送跨域请求时,携带cookie信息
xhr.withCredentials = true;
// 发送请求并传递请求参数
xhr.send();
// 监听服务器端给予的响应内容
xhr.onload = function () {
console.log(xhr.responseText);
}
}
}
</script>
- s2服务器端
- 引入express-session模块设置表单验证
- 通过formidable解析表单
- 设置跨域请求允许携带cookie
1
res.header('Access-Control-Allow-Credentials', true);
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// 接收post请求参数
const formidable = require('formidable');
// 实现session功能
var session = require('express-session');
// 设置session功能
app.use(session({
secret: 'keyboard',
resave: false,
saveUninitialized: false
}))
// 拦截所所有请求,设置是否允许跨域访问
app.use((req, res, next) => {
// 设置允许的网站
res.header('Access-Control-Allow-Origin', '*');
// 设置允许访问的请求方式
res.header('Access-Control-Allow-Methds', 'get,post');
// 允许客户端发送请求时携带cookie
res.header('Access-Control-Allow-Credentials', true);
// 转发控制权
next();
});
// 接收跨域请求
app.post('/login', (req, res, next) => {
// 创建表单解析对象formidable
var form = formidable.IncomingForm();
// 解析表单
form.parse(req, (err, fields, files) => {
//接收客户端传递过来的参数
const { username, password } = fields;
console.log(username)
console.log(password)
// 用户名密码比对
if (username == '123' && password == '123') {
// 设置session
req.session.isLogin = true;
res.send({ message: '登录成功' });
} else {
res.send({ message: '登录失败, 用户名或密码错误' });
}
})
});
app.get('/checkLogin', (req, res) => {
// 判断用户是否处于登录状态
if (req.session.isLogin) {
res.send({ message: '处于登录状态' })
} else {
res.send({ message: '处于未登录状态' })
}
});
- 执行结果
- 客户端
- 这里需要使用第三方模块express-session
7.8 ajax跨域访问限制的解决方案总结:
- jsonp方式:这里发送的不是ajax请求,而是模拟ajax方式发送请求,绕过了同源政策发送请求
- CORS跨域资源共享:客户端发送的依然是ajax请求,并没有绕过同源政策,而是在服务器设置是否允许跨域资源访问
- 服务器端解决方案:同源政策是浏览器给予Ajax技术的限制,服务器端是不存在同源政策限制.绕过了同源政策的限制,客户端发送的是ajax请求给自己服务器,将跨域请求的问题让自己的服务器端去获取信息在响应给自己的客户端(引入express框架中request第三方模块)
实践总结
- post接收参数解析的两种方式
- req.body(第三方模块body-parser)
1
2
3
4
5const bodyParser = require('body-parser');
// 设置post方式接收的内容类型
// app.use(bodyParser.urlencoded({ extended: false }));//application内容类型对应的设置
app.use(bodyParser.json());
res.send(req.body) - form.parse(内置对象DataForm)
1
2
3
4
5
6// 创建formidable表单解析对象
const form = new formidable.IncomingForm()
// 解析客户端传递过来的FormData对象
form.parse(req, (err, fields, files) => {
res.send(fields);
}); - 二者的比较
- 二者都可以解析普通的表单键值信息,
- 后者可以还能解析文件等特殊的表单,(解析表单,支持get请求参数,post请求参数、文件上传)
- bodyParser不能解析FormData数据,必须通过formidable来解析
- req.body(第三方模块body-parser)
- 在客户端书写html模板引擎是写在script标签中,并且type类型为text/html,这样保证代码的高亮性
1
<script type="text/html" id="tpl">模板引擎的转中的内容<script>
本文作者:
SparkParis
本文链接: https://sparkparis.github.io/2020/04/23/Ajax%E7%AC%94%E8%AE%B02/
版权声明: 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。转载请注明出处!
本文链接: https://sparkparis.github.io/2020/04/23/Ajax%E7%AC%94%E8%AE%B02/
版权声明: 本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。转载请注明出处!