Nodejs

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>

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值