ajax发送请求,需要传输数据,数据有不同的类型,所以也是靠请求头告诉后台处理逻辑
传输数据的方式有很多种
http: 1.0,1.1(keep-alive) 复用连接, 2.0 https 新特点双向通信,多路复用
数据交互的方式
客户端主动发送请求给服务端,服务端返回数据,我们叫单向通信
- 表单 (会页面跳转,如果是get会加个?,如果是post就会跳转业面,页面重新渲染,重新请求服务器,获取页面,这样就会浪费很多流量,对服务器压力很大) 但是一般提交我们用表单 支持跨域
- ajax 同步体验不好,可以无刷新页面 1.0,2.0 ajax基于表单请求http发过去的,只是发送方式不一样 不支持跨域
- jsop xss攻击,逐渐接口暴露出去,大家都可以访问,大多数网站在废弃中, 逐渐被cors代替
- cors 跨域资源共享,不需要前台,直接更改服务端配置
- nginx 反向代理
- webpack proxy 反向代理
双向通信 连接以后,不需要客户端主动发送请求,服务端可以主动告诉他,会实时吧最新的信息提交给客户端,之前我们的做法是setInterval,但是这就有个问题,假设我们10分钟内没有更新呢,而用websokct当服务端变了之后会主动推送给客户端,我们经常应用例如聊天室
- websocket (基于tcp)
我们通过node实现服务端,接收前端请求
表单 (会页面跳转,如果是get会加个?,如果是post就会跳转业面,页面重新渲染,重新请求服务器,获取页面,这样就会浪费很多流量,对服务器压力很大) 但是一般提交我们用表单
| get | post |
|---|---|
| 放到url里,有限制 | 不限制大小 |
get的url形式方便分享 post通过请求体
<!-- form支持什么格式提交get post 不识别默认get -->
<form action="http://localhost:3000/form" method="get">
用户名 <input type="text" name="username"><br>
密码 <input type="text" name="password"><br>
<input type="submit">
</form>
跳转之后的链接会有http://127.0.0.1:5500/?username=123&password=321form默认支持跨域
//服务端
let http = require('http');
let url = require('url');
let server = http.createServer(function(req,res){
let {pathname,query} = url.parse(req.url,true);
if(pathname === '/form'){
res.end(JSON.stringify(query))
}
})
server.listen(3000)
把方法改成post
let http = require('http');
let url = require('url');
let querystring = require('querystring');
// let str = "username==123&&password==321";
// // 指定字段之间的分隔符 和 key、value之间的分隔符-》对象
// let obj = querystring.parse(str,'&&','==');
// console.log(obj);
let server = http.createServer(function(req,res){
let {pathname,query} = url.parse(req.url,true);
let method = req.method.toLowerCase();//在node中取得的方法名永远是大写的
if(pathname === '/form'){
if(method === 'get'){
res.end(JSON.stringify(query))
}else{
let buffers = [];
//接收请求体
req.on('data',function(data){
buffers.push(data);
})
req.on('end',function(){
//表单格式接受的都是a=b&c=d
//headers[ 'content-type': 'application/x-www-form-urlencoded']
let str = Buffer.concat(buffers).toString();
res.end(JSON.stringify(querystring.parse(str)));
})
}
}
})
server.listen(3000)
表单提交的文件比较特殊
<!-- form支持什么格式提交get post 不识别默认get enctype="multipart/form-data" 多文本,内容类型:多段form表单格式 -->
<form action="http://localhost:3000/form" method="get">
用户名 <input type="text" name="username"><br>
密码 <input type="text" name="password"><br>
<input type="submit">
</form>
多段form表单格式会用分隔符将内容分离开
npm install formidable
let http = require('http');
let url = require('url');
let querystring = require('querystring');
let formidable = require('formidable')
let path = require('path')
// let str = "username==123&&password==321";
// // 指定字段之间的分隔符 和 key、value之间的分隔符-》对象
// let obj = querystring.parse(str,'&&','==');
// console.log(obj);
let server = http.createServer(function(req,res){
let {pathname,query} = url.parse(req.url,true);
let method = req.method.toLowerCase();//在node中取得的方法名永远是大写的
if(pathname === '/form'){
if(method === 'get'){
res.end(JSON.stringify(query))
}else{
var form = new formidable.IncomingForm();
//fields a=b&c=d文本 files文件
form.keepExtensions = true;//保留后缀
form.encoding = 'utf-8';
form.uploadDir = path.join(__dirname,'./myDir');
form.parse(req, function(err, fields, files) {
});
form.on('end', function() {
res.end('上传成功');
});
}
}
})
server.listen(3000)
ajax 同步体验不好,可以无刷新页面 1.0,2.0 ajax基于表单请求http发过去的,只是发送方式不一样
<!-- 不支持跨域,协议,主机名,端口号 表单的好处可以加自己的校验-->
<form onsubmit="login(event)" id="form">
用户名:
<input type="text" name="username" required>
<br> 密码:
<input type="text" name="password">
<br>
<input type="submit" value="提交">
</form>
function login(e) {
let $ = document.querySelector.bind(document);
function serialized(ele) {
let arr = [];
let elements = ele.elements;
for (let i = 0; i < elements.length; i++) {
let { type, name, value } = elements[i];
switch (type) {
case 'text':
case 'password':
arr.push(`${name}=${value}`);
break
default:
}
}
return arr.join('&');
}
function login(e) {
//阻止默认行为
e.preventDefault();
//表单序列化 username=123&password=456
let qs = serialized($('#form'));
//ajax4步
let xhr = new XMLHttpRequest();
xhr.open('GET', `/2.html?${qs}`, true); // true代表是否异步
xhr.responseType = 'json';// 服务返回的应该是一个对象
xhr.timeout = 3000; // 3000过去了还没有数据返回就是超时
xhr.ontimeout = function () {
console.log('超时')
}
xhr.onerror = function (err) {//断网
console.log(err);
}
xhr.setRequestHeader('Content-Type', 'application/www-x-form-urlencoded');
// xhr.setRequestHeader('Content-Type','application/json')
//readyState 0 表示还没有open 1代表open了 2 代表发送求求 3.接收到了部分请求
xhr.onreadystatechange = function () {
console.log(xhr.readyState);
console.log(xhr.status)
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {
console.log(xhr.response);
}
}
}
xhr.send(qs);
}
需要启动服务否则跨域
//服务代码
let http = require('http');
let url = require('url');
let fs = require('fs');
let path = require('path');
let querystring = require('querystring');
let server = http.createServer(function (req,res) {
let {pathname,query} = url.parse(req.url,true);
if(pathname === '/2.html'){
let method = req.method.toLowerCase();
if(method === 'get'){ //get方法
res.end(JSON.stringify(query));
}else{//post方法
let buffers = [];
req.on('data', function (data) {
buffers.push(data);
});
req.on('end', function () {
let str = Buffer.concat(buffers).toString();
console.log(str);
res.end(JSON.stringify(querystring.parse(str)));
})
}
return
}
if(pathname === '/'){
return fs.createReadStream(path.join(__dirname,'./1.html')).pipe(res);
}
let p = path.join(__dirname, pathname);
fs.stat(p,function (err,stat) {
if(!err){
fs.createReadStream(p).pipe(res);
}else{
res.statusCode = 404;
res.end(`NotFound`);
}
})
});
server.listen(3000);
post请求和get形似
我们队上述ajax做个简单的封装
function login(e) {
//阻止默认行为
e.preventDefault();
//表单序列化 username=123&password=456
let qs = serialized($('#form'));
//ajax4步
let xhr = new XMLHttpRequest();
ajax({
url: '/2.html',
method: 'post',
dataType: 'json',
contentType:'application/www-x-form-urlencoded',//只有post需要传
data: qs
}).then(data=>{
console.log(data);
}).catch(e=>{
console.log(e);
});
}
function ajax(options) {
return new Promise((resolve,reject)=>{
let {
url = new Error('url must a string'),
method = "get",
dataType = "text",
data = null,
success,
contentType,
error
} = options;
let xhr = new XMLHttpRequest();
if (method == 'get') {
xhr.open(method, `${url}?${data}`, true);//如果是get请求,要将数据拼接到url
} else {
xhr.open(method, url, true);
xhr.setRequestHeader('ContentType', contentType);//设置请求头
}
xhr.responseType = dataType;//响应类型
xhr.onerror = function (err) {
error && error(err);
reject(err)
}
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300 || xhr.status === 304) {
console.log(xhr.response)
success && success(xhr.response);
resolve(xhr.response)
}
}
}
data = method === 'get' ? null : data;
xhr.send(data);
})
}