1.http模块
Node.js 是js运行时环境 可以解析执行js代码 以前只有浏览器可以 所以现在js可以脱离浏览器来运行。
Node.js 的js 没有dom bom 服务端不处理页面,仅提供服务端API,如文件读写 网络服务构建 网络通信 http服务器 。。。
Node.js 事件驱动 非阻塞IO模型(异步)轻量高效 npm 世界上最大的开源生态系统 绝大多数js包都放在了npm上 方便下载
var http = require('http')
var server = http.createserver()
server.on('request', function(request, response){ //注册request 事件 当客户端请求过来 自动触发服务器的request请求事件调用第二个参数 回调处理 function需要两个参数
console.log(request.url)
response.write('hello')//可写多次 但最后一次要以end结束 否则客户端会一直都能
response.end()
})
server.listen(3000,function(){
})//绑定端口号 启动服务 当启动成功 调用回调函数
使用 url.parse 方法将路径解析为一个方便操作的对象,第二个参数为 true 表示直接将查询字符串转为一个对象(通过 query 属性来访问)
var parseObj = url.parse(req.url, true)
单独获取不包含查询字符串的路径部分(该路径不包含 ? 之后的内容)
var pathname = parseObj.pathname
else if (pathname === '/pinglun') {
注意:这个时候无论 /pinglun?xxx 之后是什么,我都不用担心了,因为我的 pathname 是不包含 ? 之后的那个路径
一次请求对应一次响应,响应结束这次请求也就结束了
res.end(JSON.stringify(parseObj.query))
我们已经使用 url 模块的 parse 方法把请求路径中的查询字符串给解析成一个对象了
所以接下来要做的就是:
1. 获取表单提交的数据 parseObj.query
2. 将当前时间日期添加到数据对象中,然后存储到数组中
3. 让用户重定向跳转到首页 /
当用户重新请求 / 的时候,我数组中的数据已经发生变化了,所以用户看到的页面也就变了
var comment = parseObj.query
comment.dateTime = '2017-11-2 17:11:22'
comments.unshift(comment)
服务端这个时候已经把数据存储好了,接下来就是让用户重新请求 / 首页,就可以看到最新的留言内容了
实现登录注册:
const http=require('http');
const url=require('url');
const querystring=require('querystring');
const fs=require('fs');
let users={
// 'blue': '123456',
// 'zhangsan': '654321'
};
let server=http.createServer((req, res)=>{
//GET
let {pathname, query}=url.parse(req.url, true);
//POST
let str='';
req.on('data', data=>{
str+=data;
});
req.on('end', ()=>{
let post=querystring.parse(str);
let {user, pass}=query;
//写东西
switch(pathname){
case '/reg': //注册
if(!user){
res.write('{"err": 1, "msg": "user is required"}');
}else if(!pass){
res.write('{"err": 1, "msg": "pass is required"}');
}else if(!/^\w{8,32}$/.test(user)){
res.write('{"err": 1, "msg": "invaild username"}');
}else if(/^['|"]$/.test(pass)){
res.write('{"err": 1, "msg": "invaild password"}');
}else if(users[user]){
res.write('{"err": 1, "msg": "username already exsits"}');
}else{
users[user]=pass;
res.write('{"err": 0, "msg": "success"}');
}
res.end();
break;
case '/login': //登陆
if(!user){
res.write('{"err": 1, "msg": "user is required"}');
}else if(!pass){
res.write('{"err": 1, "msg": "pass is required"}');
}else if(!/^\w{8,32}$/.test(user)){
res.write('{"err": 1, "msg": "invaild username"}');
}else if(/^['|"]$/.test(pass)){
res.write('{"err": 1, "msg": "invaild password"}');
}else if(!users[user]){
res.write('{"err": 1, "msg": "no this user"}');
}else if(users[user]!=pass){
res.write('{"err": 1, "msg": "username or password is incorrect"}');
}else{
res.write('{"err": 0, "msg": "login success"}');
}
res.end();
break;
default: //其他:文件
fs.readFile(`www${pathname}`, (err, data)=>{
if(err){
res.writeHeader(404);
res.write('Not Found');
}else{
res.write(data);
}
res.end();
});
}
});
});
server.listen(8080);
const http=require('http');
const mysql=require('mysql');
const fs=require('fs');
const url=require('url');
const zlib=require('zlib');
const crypto=require('crypto');
const _key='sadfslekrtuew5iutoselgdtjiypoydse4ufhs.edtyo;s8te4arfeliawkfhtsie5tlfia;sefdshroiupeoutwyeli5gurse;ihf';
function md5(str){
let obj=crypto.createHash('md5');
obj.update(str);
return obj.digest('hex');
}
function md5_2(str){
return md5(md5(str)+_key);
}
let db=mysql.createPool({host: 'localhost', port: 3309, user: 'root', password: '', database: '20180127'});
let server=http.createServer((req, res)=>{
let {pathname, query}=url.parse(req.url, true);
let {user, pass}=query;
switch(pathname){
//接口
case '/reg':
//校验
if(!user){
res.write('{"err": 1, "msg": "username can\'t be null"}');
res.end();
}else if(!pass){
res.write('{"err": 1, "msg": "password can\'t be null"}');
res.end();
}else if(!/^\w{4,16}$/.test(user)){
res.write('{"err": 1, "msg": "username is invaild"}');
res.end();
}else if(/['|"]/.test(pass)){
res.write('{"err": 1, "msg": "password is invaild"}');
res.end();
}else{
db.query(`SELECT * FROM user_table WHERE username='${user}'`, (err, data)=>{
if(err){
res.write('{"err": 1, "msg": "database error"}');
res.end();
}else if(data.length>0){
res.write('{"err": 1, "msg": "this username exsits"}');
res.end();
}else{
db.query(`INSERT INTO user_table (ID,username,password) VALUES(0,'${user}','${md5_2(pass)}')`, (err, data)=>{
if(err){
res.write('{"err": 1, "msg": "database error"}');
res.end();
}else{
res.write('{"err": 0, "msg": "success"}');
res.end();
}
});
}
});
}
break;
case '/login':
//校验
if(!user){
res.write('{"err": 1, "msg": "username can\'t be null"}');
res.end();
}else if(!pass){
res.write('{"err": 1, "msg": "password can\'t be null"}');
res.end();
}else if(!/^\w{4,16}$/.test(user)){
res.write('{"err": 1, "msg": "username is invaild"}');
res.end();
}else if(/['|"]/.test(pass)){
res.write('{"err": 1, "msg": "password is invaild"}');
res.end();
}else{
db.query(`SELECT * FROM user_table WHERE username='${user}'`, (err, data)=>{
if(err){
res.write('{"err": 1, "msg": "database error"}');
res.end();
}else if(data.length==0){
res.write('{"err": 1, "msg": "no this user"}');
res.end();
}else if(data[0].password!=md5_2(pass)){
res.write('{"err": 1, "msg": "username or password is incorrect"}');
res.end();
}else{
res.write('{"err": 0, "msg": "success"}');
res.end();
}
});
}
break;
default:
//缓存 TODO
//静态文件
let rs=fs.createReadStream(`www${pathname}`);
let gz=zlib.createGzip();
res.setHeader('content-encoding', 'gzip');
rs.pipe(gz).pipe(res);
rs.on('error', err=>{
res.writeHeader(404);
res.write('Not Found');
res.end();
});
}
});
server.listen(8080);
如何通过服务器让客户端重定向?
1. 状态码设置为 302 临时重定向
statusCode
2. 在响应头中通过 Location 告诉客户端往哪儿重定向
setHeader
如果客户端发现收到服务器的响应的状态码是 302 就会自动去响应头中找 Location ,然后对该地址发起新的请求
所以你就能看到客户端自动跳转了
res.statusCode = 302
res.setHeader('Location', '/')
res.end()
2.断言——assert
const assert=require('assert');
function sum(a, b){
assert(arguments.length==2, '必须传2个参数');
assert(typeof a=='number', '第一个参数必须是数字');
assert(typeof b=='number', '第二个参数必须是数字');
return a+b;
}
console.log(sum(12, 5));
3. File System
const fs=require('fs');
fs.readFile('ofo.png', (err, data)=>{
fs.writeFile('ofo2.png', data, ()=>{});
});
4.Crypto——签名
md5、sha
const crypto=require('crypto');
function md5(str){
let obj=crypto.createHash('md5');
obj.update(str);
return obj.digest('hex');
}
console.log(md5(md5('123456')+'se32ssdfsd43'));
5.stream
const zlib=require('zlib');
const fs=require('fs');
let rs=fs.createReadStream('jquery.js');
let ws=fs.createWriteStream('jquery.js.gz');
let gz=zlib.createGzip();
rs.pipe(gz).pipe(ws);
ws.on('finish', ()=>{
console.log('完成');
});
6.cluster
const http=require('http');
const cluster=require('cluster');
const os=require('os');
const process=require('process');
if(cluster.isMaster){
for(let i=0;i<os.cpus().length;i++){
cluster.fork();
}
console.log('主进程');
}else{
let server=http.createServer((req, res)=>{
console.log(process.pid);
res.write('aaaa');
res.end();
});
server.listen(8080);
console.log('服务器开好了,在8080上');
}
7.if-modified-since
const http=require('http');
const fs=require('fs');
const url=require('url');
http.createServer((req, res)=>{
let {pathname}=url.parse(req.url);
//获取文件日期
fs.stat(`www${pathname}`, (err, stat)=>{
if(err){
res.writeHeader(404);
res.write('Not Found');
res.end();
}else{
if(req.headers['if-modified-since']){
let oDate=new Date(req.headers['if-modified-since']);
let time_client=Math.floor(oDate.getTime()/1000);
let time_server=Math.floor(stat.mtime.getTime()/1000);
if(time_server>time_client){ //服务器的文件时间>客户端手里的版本
sendFileToClient();
}else{
res.writeHeader(304);
res.write('Not Modified');
res.end();
}
}else{
sendFileToClient();
}
function sendFileToClient(){
//发送
let rs=fs.createReadStream(`www${pathname}`);
res.setHeader('Cache-Control', 'no-cache');
res.setHeader('Last-Modified', stat.mtime.toGMTString());
//输出
rs.pipe(res);
rs.on('error', err=>{
res.writeHeader(404);
res.write('Not Found');
res.end();
});
}
}
});
}).listen(8080);
8.数据库
const mysql=require('mysql');
let db=mysql.createConnection({host: 'localhost', user: 'root', password: '', port: 3309, database: '20180127'});
db.query(`INSERT INTO user_table (ID, name, gender, chinese, math, english) VALUES(0, '小明', '男', 98, 5, 3);`, (err, data)=>{
if(err){
console.log('错了', err);
}else{
console.log(data);
}
});
const mysql=require('mysql');
//连接池
let db=mysql.createPool({host: 'localhost', user: 'root', password: '', port: 3309, database: '20180127'});
db.query(`INSERT INTO student_table (ID, name, gender, chinese, math, english) VALUES(0, '小明', '男', 98, 5, 3);`, (err, data)=>{
if(err){
console.log('错了', err);
}else{
console.log(data);
}
});
用 createConnection
创建 Mysql 连接,每执行一次 connection.query
都是一个全新的连接,会造成一个资源的极大浪费,降低性能。
连接池是另外的一种执行方法,它一次性的创建了多个连接,然后根据客户端的查询,自动的 分发
、复用
、管理
这些连接。
SQL 注入
在写 SQL 语句的时间尽量不要使用 SQL 拼装,因为很容易被 SQL注入
,从而引发安全问题,如果数据和 SQL 语句需要分离,那么请使用 占位符
的方式。
connection.query("select * from users where id = ? and name = ?", [1, 'jmjc'], (err, result)=>{}) // 这种方式 mysql 模块内部会调用 escape 方法,过滤掉一些非法的操作
/*
当前我们也可以自己使用 escape 方法
*/
connection.query('select * from users where id = ' + connection.escape(userId), (err, result) => {})
/*
或者 format 方法
*/
const sql = "select * from ?? where ?? = ?"
const inserts = ['users', 'id', 1]
sql = mysql.format(sql, inserts) // select * from users where id = 1
9.socket.io
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script src="http://localhost:8080/socket.io/socket.io.js" charset="utf-8"></script>
<script>
let sock=io.connect('ws://localhost:8080/');
//sock.emit
//sock.on
//sock.emit('aaa', 12, 5, 8);
sock.on('t', function (ts){
console.log(ts);
});
</script>
</head>
<body>
</body>
</html>
server:
const http=require('http');
const io=require('socket.io');
let httpServer=http.createServer();
httpServer.listen(8080);
let wsServer=io.listen(httpServer);
wsServer.on('connection', sock=>{
//sock.emit 发送
//sock.on 接收
/*sock.on('aaa', function (a, b, c){
console.log(a, b, c);
});*/
setInterval(function (){
sock.emit('t', new Date().getTime());
}, 1000);
});
socket.io
服务端:
sock.on('connection')
sock.on('disconnect')
客户端:
sock.on('connect')
sock.on('disconnect')
server:
const http=require('http');
const io=require('socket.io');
let httpServer=http.createServer((req, res)=>{
});
httpServer.listen(8080);
//
let wsServer=io.listen(httpServer);
let aSock=[];
wsServer.on('connection', sock=>{
aSock.push(sock);
//断开连接
sock.on('disconnect', ()=>{
let n=aSock.indexOf(sock);
if(n!=-1){
aSock.splice(n, 1);
}
});
sock.on('msg', str=>{
aSock.forEach(s=>{
if(s!=sock){
s.emit('msg', str);
}
});
});
});
setInterval(function (){
console.log(aSock.length);
}, 500);
client:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style media="screen">
#ul1 {width:400px; height:300px; border:1px solid black; overflow:auto;}
#ul1 li.me {color:green}
.err_box {width:100%; height:20px; line-height: 20px; text-align:center; color:red; display:none}
</style>
<script src="http://localhost:8080/socket.io/socket.io.js" charset="utf-8"></script>
<script>
let sock=io.connect('ws://localhost:8080/');
sock.on('connect', ()=>{
document.getElementsByClassName('err_box')[0].style.display='none';
});
sock.on('disconnect', ()=>{
document.getElementsByClassName('err_box')[0].style.display='block';
});
//聊天室
window.onload=function (){
let oTxt=document.getElementById('txt1');
let oBtn=document.getElementById('btn1');
let oUl=document.getElementById('ul1');
oBtn.onclick=function (){
sock.emit('msg', oTxt.value);
let oLi=document.createElement('li');
oLi.innerHTML=oTxt.value;
oLi.className='me';
oTxt.value='';
oUl.appendChild(oLi);
};
sock.on('msg', str=>{
let oLi=document.createElement('li');
oLi.innerHTML=str;
oUl.appendChild(oLi);
});
};
</script>
</head>
<body>
<div class="err_box">
无法连接到服务器,请检查网络
</div>
<ul id="ul1"></ul>
<textarea rows="4" cols="60" id="txt1"></textarea>
<input type="button" value="发送" id="btn1">
</body>
</html>
原生websocket:
WebSocket是前台的东西,是HTML5带的一种东西
1.只有前台有WebSocket这个东西
2.后台没有,后台有Socket
用WebSocket:
1.socket.io
2.原生WebSocket
i.net模块
ii.流程
a.握手
C:version:13、sec-websocket-key:xxxxx、sha1(key+mask)=>base64
S:101 Switching Protocols、sec-websocket-accept: base64
C <-> S
Client:
onopen
onmessage
onclose
Server:
net.createServer(sock=>{});
sock.once('data', 握手);
sock.on('data', 数据请求);
sock.on('end');
b.数据帧解析
0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| opcode|M| Payload len | Extended payload length |
|I|S|S|S| (4) |A| (7) | (16/64) |
|N|V|V|V| |S| | (if payload len==126/127) |
| |1|2|3| |K| | |
+-+-+-+-+-------+-+-------------+-------------------------------+
| Extended payload length continued, if payload len == 127 |
+-------------------------------+-------------------------------+
| |Masking-key, if MASK set to 1 |
+-------------------------------+-------------------------------+
| Masking-key (continued) | Payload Data |
+-------------------------------+-------------------------------+
| Payload Data continued ... |
+---------------------------------------------------------------+
| Payload Data continued ... |
+---------------------------------------------------------------+
FIN 1bit 是否最后一帧
RSV 3bit 预留
Opcode 4bit 帧类型
Mask 1bit 掩码,是否加密数据,默认必须置为1
Payload 7bit 长度
Masking-key 1 or 4 bit 掩码
Payload data (x + y) bytes 数据
Extension data x bytes 扩展数据
Application data y bytes 程序数据
server:
const http=require('http');
const net=require('net'); //TCP 原生Socket
const crypto=require('crypto');
/*
let server=http.createServer((req, res)=>{
console.log('连接');
});
server.listen(8080);
*/
let server=net.createServer(sock=>{
console.log('连接');
//数据过来——握手只有一次
sock.once('data', data=>{
console.log('hand shake start...');
let str=data.toString();
let lines=str.split('\r\n');
//舍弃第一行和最后两行
lines=lines.slice(1, lines.length-2);
//切开
let headers={};
lines.forEach(line=>{
let [key, val]=line.split(': ');
headers[key.toLowerCase()]=val;
});
//console.log(headers);
if(headers['upgrade']!='websocket'){
console.log('其他协议', headers['upgrade']);
sock.end();
}else if(headers['sec-websocket-version']!=13){
console.log('版本不对', headers['sec-websocket-version']);
sock.end();
}else{
let key=headers['sec-websocket-key'];
let mask='258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
//sha1(key+mask)->base64=>client
let hash=crypto.createHash('sha1');
hash.update(key+mask);
let key2=hash.digest('base64');
sock.write(`HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: ${key2}\r\n\r\n`);
console.log('hand shake end');
//真正的数据
sock.on('data', data=>{
console.log('有数据');
let FIN=data[0]&0x001;
let opcode=data[0]&0x0F0;
let mask=data[1]&0x001;
let payload=data[1]&0x0FE;
console.log(FIN, opcode);
console.log(mask, payload);
});
}
});
//断开了
sock.on('end', ()=>{
console.log('客户端已断开');
});
});
server.listen(8080);
client:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script>
let sock=new WebSocket('ws://localhost:8080/');
sock.emit=function (name, ...args){
alert(JSON.stringify({name, data: [...args]}));
sock.send(JSON.stringify({name, data: [...args]}));
};
//连上了
sock.onopen=function (){
alert('连接上了');
sock.emit('msg', 12, 5);
};
//有数据
sock.onmessage=function (){
alert('有消息过来');
};
//断开了
sock.onclose=function (){
alert('断了');
};
</script>
</head>
<body>
</body>
</html>
ajax2.0
a.formdata:控制提交数据、文件上传
b.cors跨域
formdata:
set(key, value) 会覆盖
append(key, value) 不覆盖
get(key)=>value
delete(key)
data.set('user', 'blue');
data.set('user', 'blue2');
<form>
<input type="text" name="user" value="blue" />
<input type="text" name="user" value="blue2" />
</form>
FormData——上传文件
1.set、get、getAll、forEach、delete
2.服务器那边——跟普通<form>一样的
<script>
let data=new FormData();
data.set('user', 'blue');
data.append('user', 'blue2');
console.log(data.getAll('user'));
</script>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script>
window.onload=function (){
let oUser=document.getElementById('user');
let oPass=document.getElementById('pass');
let oBtn=document.getElementById('btn1');
oBtn.onclick=function (){
let data=new FormData();
data.set('user', oUser.value);
data.set('pass', oPass.value);
//
let oAjax=new XMLHttpRequest();
//GET
let arr=[];
data.forEach((value, key)=>{
arr.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);
});
oAjax.open('GET', `http://localhost:8080/api?${arr.join('&')}`, true);
oAjax.setRequestHeader('my-origin-blue', window.location.hostname);
oAjax.send();
//POST
/*oAjax.open('POST', `http://localhost:8080/api`, true);
oAjax.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
oAjax.send(data);*/
oAjax.onreadystatechange=function (){
if(oAjax.readyState==4){
if(oAjax.status>=200 && oAjax.status<300 || oAjax.status==304){
alert('成功:'+oAjax.responseText);
}else{
alert('失败');
}
}
};
};
};
</script>
</head>
<body>
用户:<input type="text" id="user" /><br>
密码:<input type="password" id="pass" /><br>
<input type="button" value="提交" id="btn1">
</body>
</html>
server:
const http=require('http');
const urlLib=require('url');
const querystring=require('querystring');
http.createServer((req, res)=>{
console.log(req.headers['my-origin-blue']);
//if(req.headers['origin']=='null' || /^https?:\/\/(\w+\.)+abc\.com/.test(req.headers['origin'])){
if(req.headers['origin']=='null' || req.headers['origin'].startsWith('http://localhost')){
res.setHeader('Access-Control-Allow-Origin', '*');
}
let {pathname: url, query: get}=urlLib.parse(req.url, true);
let arr=[];
req.on('data', data=>{
arr.push(data);
});
req.on('end', ()=>{
let post=querystring.parse(Buffer.concat(arr).toString());
console.log(url, get, post);
res.write('asdfasdf');
res.end();
});
}).listen(8080);
post client:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<script>
window.onload=function (){
let oUser=document.getElementById('user');
let oPass=document.getElementById('pass');
let oF=document.getElementById('f1');
let oBtn=document.getElementById('btn1');
oBtn.onclick=function (){
let data=new FormData();
data.set('user', oUser.value);
data.set('pass', oPass.value);
Array.from(oF.files).forEach(file=>{
data.append('f1', file);
});
//
let oAjax=new XMLHttpRequest();
//POST
oAjax.open('POST', `http://localhost:8080/api`, true);
oAjax.send(data);
oAjax.onreadystatechange=function (){
if(oAjax.readyState==4){
if(oAjax.status>=200 && oAjax.status<300 || oAjax.status==304){
alert('成功');
}else{
alert('失败');
}
}
};
};
};
</script>
</head>
<body>
用户:<input type="text" id="user" /><br>
密码:<input type="password" id="pass" /><br>
头像:<input type="file" id="f1" multiple /><br>
<input type="button" value="提交" id="btn1">
</body>
</html>
server:
const express=require('express'); //主体
const body=require('body-parser'); //接收普通POST数据
const multer=require('multer'); //接收文件POST数据
//let server=http.createServer((req, res)=>{});
//server.listen(8080);
let server=express();
server.listen(8080);
//中间件
server.use(body.urlencoded({extended: false}));
let multerObj=multer({dest: './upload/'});
server.use(multerObj.any());
//处理请求
server.post('/api', (req, res)=>{
if(req.headers['origin']=='null' || req.headers['origin'].startsWith('http://localhost')){
res.setHeader('Access-Control-Allow-Origin', '*');
}
res.send("OK");
console.log(req.body); //普通POST数据
console.log(req.files); //文件POST数据
});
//
server.use(express.static('./www/'));
加进度条
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style media="screen">
* {margin:0; padding:0}
.box {width:400px; height:200px; background:#CCC; border:1px solid black; line-height:200px; position:absolute; left:50%; top:50%; margin-left:-200px; margin-top:-100px; text-align:center; display:none;}
</style>
<script>
window.onload=function (){
let oBox=document.querySelector('.box');
let timer;
document.addEventListener('dragover', (ev)=>{
clearTimeout(timer);
oBox.style.display='block';
timer=setTimeout(function (){
oBox.style.display='none';
}, 300);
ev.preventDefault();
}, false);
oBox.addEventListener('dragenter', ()=>{
oBox.innerHTML='请松手';
}, false);
oBox.addEventListener('dragleave', ()=>{
oBox.innerHTML='请把文件拖到这儿';
}, false);
oBox.addEventListener('drop', (ev)=>{
let data=new FormData();
Array.from(ev.dataTransfer.files).forEach(file=>{
data.append('f1', file);
});
let oAjax=new XMLHttpRequest();
//POST
oAjax.open('POST', `http://localhost:8080/api`, true);
oAjax.upload.addEventListener('progress', function (ev){
let oM=document.querySelector('#m1');
oM.value=100*ev.loaded/ev.total;
}, false);
oAjax.send(data);
ev.preventDefault();
oAjax.onreadystatechange=function (){
if(oAjax.readyState==4){
if(oAjax.status>=200 && oAjax.status<300 || oAjax.status==304){
alert('成功');
}else{
alert('失败');
}
}
};
}, false);
};
</script>
</head>
<body>
<meter id="m1" min="0" max="100" style="width:100%;"></meter>
<div class="box">
请把文件拖到这儿
</div>
</body>
</html>