node专题

node.js学习笔记

2020-03-15  本文已影响0人  Mstian

node.js学习笔记

node

01

什么是node?

优点:处理高并发比较好

模块化

自定义模块使用模块步骤

1.创建一个模块(一个js文件一个模块)

2.导出一个模块(module.exports = name)

3.引入一个模块并且调用

运行环境

REPL :在命令行执行的环境。

内置文件模块fs

文件操作

创建文件(覆盖写入)

  fs.writeFile(path,option,callback)

写入文件(追加写入)

  fs.appendFile(path,option,callback)

读取文件

fs.readFile(path,config,(err,msg)=>{
  //msg默认为buffer数据流 可以使用 msg.toString('utf8')转换数据
  //也可以使用config出配置‘utf8’
})

删除文件

fs.unlink(path,callback)

内置url模块

url : 统一资源定位符

url.parse();将url字符串转换为对象

url.format();将url对象转换为字符串

内置querystring模块

qs.parse(str,query1,query2);
//query1 表示以什么符号切分键值对 默认 &
//query2 表示以什么符号切分键与值 默认 = 
qs.stringify(obj,query1,query2);
//query1 表示以什么符号拼接键值对 默认 &
//query2 表示以什么符号拼接键与值 默认 =
qs.escape() //编码
 
qs.unescape() //解码

第三方模块

nodemailer 可以实现发邮件

"use strict";
const nodemailer = require("nodemailer");

// 创建一个发送器
let transporter = nodemailer.createTransport({
    host: "smtp.qq.com",
    port: 465,
    secure: true, // true for 465, false for other ports
    auth: {
        user: '572410049@qq.com', // 发送者邮箱地址
        pass: 'pwuepzqfdpjybeid' // 发送者SMTP密码
    }
});

// 配置发送信息对象
var emailconfig = {
    from: '572410049@qq.com', // 发送者邮箱地址
    to: "572410049@qq.com", // 接受者邮箱地址
    subject: "你好", // 主题
    text: "准备睡觉吧", // 内容 只能是纯文本 与 html 配置项只能存在一个
    // html: "<b>Hello world?</b>" // html body
}

// 调用sendMail()方法
transporter.sendMail(emailconfig);

爬虫案例

1.获取目标网站
2.分析网站内容
3.获取有效信息 下载或其他操作

http 模块

http模块负责发请求:

const http = require('https');
let html = '';
http.get(url,(res)=>{

  let { statusCode } = res; //状态码
  let contentType = res.headers['content-type']; //请求类型
  let err = null;
  if(statusCode !== 200){
    err = new Error('请求状态出错');
  }else if(!/^text\/html/.test(contentType)){
    err = new Error('请求类型出错');
  }

  if(err){
    console.log(err);//此处可以确定错误类型
    res.resume(); //重置缓存
    return false //终止程序
  }
  //---------------------------- 代码健壮判断抓取的是否为所需类型,和是否能访问目标地址 ----------------------------------------
  res.on('data',(chunk)={
    //chunk 为buffer数据流 需通过chunk.toString('utf8')转换
    //爬取中。。。
    html += chunk.toString('utf8')
  });
  res.on('end',()=>{
    console.log(html);
    //爬取结束。
  })
}).on('error',(e)=>{
  console.log('请求出错')
})

cheerio 模块

将一组html格式的字符串 转化为类之后可以通过jq的语法选中其中的元素。

const cheerio = require('cheerio');
//将一组html格式的字符串 转化为类之后可以通过jq的语法选中其中的元素。
var div = '<div> <img src="http://www.baidu.com"/> </div>'
const $ = cheerio.load(div);

console.log($('img').attr('src'));

实现抓取一个页面的图片

const http = require('https');
const fs = require('fs');
const cheerio = require('cheerio');
const request = require('request');
const reg = /(http|https):\/\/([\w.]+\/?)\S*/ig
let url = 'https://www.zcool.com.cn/';
let html = '';
http.get(url, (res) => {
    let { statusCode } = res; //状态码
    let contentType = res.headers['content-type']; //请求类型
    let err = null;
    if (statusCode !== 200) {
        err = new Error('请求状态错误')
        //请求状态错误
    } else if (!/^text\/html/.test(contentType)) {
        //请求类型错误
        err = new Error('请求类型错误')
    }
    if (err) {
        console.log(err);
        res.resume(); //重置缓存
        return;
    }
    res.on('data', (chunk) => {
        html += chunk.toString('utf8');
        // console.log('爬取中')
    });
    res.on('end', () => {
        console.log(html);
        const $ = cheerio.load(html)
        $('img').each((index, el) => {
            if (reg.test($(el).attr('src'))) { //判断是否是以http 或者https 开头的
                request($(el).attr('src')).pipe(  //下载到本地
                    fs.createWriteStream(`./node/${index}.png`).on('close', err => {
                        console.log('下载成功', err)
                    })
                )
            }
        })
    })
  }).on('error', (e) => {
     console.log('出错啦');
  })

02

通过express 框架书写api

1.安装 express

npm install express --save

模块(第三方模块)的引用 从当前目录的node_modules依次向上寻找。

服务器相关

服务器:

1.服务器本质就是一台电脑

2.需要服务器软件(apatch tomcat iis nginx node)

3.服务器ip和端口号 (80)

局域网:服务器通过(无线)网线连接 每一台电脑都被分配一个ip

外网:

ip:确定服务器主机的位置

port:是确定服务器里程序的位置

api接口

构成要素:ip port pathname method(get,post) data

中间件 middlewear

中间件使用一定要注意 next);

中间件有全局中间件,还有局部中间件,局部中间只走该中间件所在接口。

static 静态目录 (类似apche www目录)

path 模块 处理路径

对文件操作 必须使用绝对路径

__dirname 绝对路径

static 模块使用

app.use('./',express.static(path.join(__dirname,'./html')));

此时 可以通过http://localhost:3000/index.html 访问html文件夹下的index.html文件

node router

防止一个文件写过多接口造成不良影响,拆分接口到对应文件

server.js

const express = require('express');
const app = express();
const bodyParser = require('body-parser');

app.use(bodyParser.json());

app.use('/',(req,res,next)=>{
    if(req.query.token || req.body.token){
        next()
    }else{
        res.send('no token')
    }
});
//引入各个router
const userRouter = require('./router/user');
const customRouter = require('./router/custom');
//使用各个router
app.use('/user',userRouter);
app.use('/custom',customRouter);

app.listen(3000,()=>{
    console.log('server start');
})

router/user.js

const express = require('express');
const router = express.Router(); //实例化router

router.get('/login',(req,res)=>{
    res.send('login ok')
})

router.get('/logout',(req,res)=>{
    res.send('logout ok');
})

module.exports = router; //导出

非关系数据库 mongodb

1.mongodb 下载 (下载速度慢问题解决mongodb下载慢问题

2.安装 建议参考菜鸟教程 mongodb安装 菜鸟教程mongodb windows安装

指令

mongodb 数据库名

mongod 命令行启动数据库

mongo 命令行操作数据库指令

mongoose node操作mongodb的插件

promise

为什么要是用promise?

大量的异步操作如果需要顺序执行通过回调函数会形成回调地狱

通过promise解决回调地狱

1.封装promise函数

//使用形式
//返回promise
function test(){
  return new Promise((resolve,reject)=>{
    //异步处理
    //成功的时候
    resolve();
    //失败的时候
    reject();
  })
}

2.根据顺序,形成链式调用
test().then().then();

在第一个then中需再return出一个promise对象

3.捕获错误

示例代码:

const fs = require('fs');
//回调形式
// fs.stat('./aaa.js',(err,stats)=>{ 
//     if(err){
//         console.log('文件不存在')
//     }else{
//         console.log('文件存在');
//         fs.unlink('./aaa.js',(err)=>{
//             if(err){
//                 console.log('删除错误');
//             }else{
//                 console.log('删除正确');
//             }
//         })
//     }
// })

//promise形式
function fileIsExsit(){
    return new Promise((resolve,reject)=>{
        fs.stat('./aaa.js',(err,stats)=>{
            if(err){
                console.log('不存在')
                reject('err')
            }else{
                console.log('存在')
                resolve('yes')
            }
        })
    })
}

function filedel(){
    return new Promise((resolve,reject)=>{
        fs.unlink('./aaa.js',(err)=>{
            if(err){
                reject('删除失败')
            }else{
                resolve('删除成功')
            }
        })
    })
}

fileIsExsit()
.then((data)=>{
    console.log(data,'------------then')
    return filedel();
})
.then((data)=>{
    console.log(data,'----then')
    //如何手动终止then?
    throw new Error('手动抛出错误,为了手动终止then执行');
})
.then((a)=>{
    console.log(111);
})
.catch((data)=>{
    console.log(data,'------------catch')
})

mongoose

mongoose:为了方便操作数据库而诞生的一个模块

1.安装mongoose:

npm install mongoose

2.引入模块,连接数据库

const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/users',{ useNewUrlParser: true,useUnifiedTopology: true })
//第一个参数为本地数据库,第二个参数为mongoose.connect()方法新增的参数,否则会warning

3.创建数据库连接对象

var db = mongoose.connection;
db.on('error',console.error.bind(console,'connection error:')) //监听错误
db.on('open',function(){ //监听连接成功
  console.log('数据库连接成功');
})

4.创建schema对象

var userSchema = new mongoose.Schema({
  name:String,
  age:Number,
  sex:{
    type:Number,
    default:0
  },  
})

5.创建model结构

//将schema对象转换为数据模型
//将schema对象与集合关联('集合名',schema对象);注意:集合名mongoose会自动转换成复数形式因此建议集合名使用复数形式
var User = mongoose.model('users',userSchema);

6.操作数据库

//增 
//insertMany([options]) options 可为数组 可为对象 是追加操作,会追加到当前表的数据末尾
// User.insertMany([{name:'tll',age:18},{name:'zt',age:18,sex:0},{name:'ah',age:18,sex:0}])
// .then((data)=>{
//     console.log(data);
//     console.log('插入成功');
// })
// .catch((data)=>{
//     console.log('插入失败');
// })

// 删
// deleteOne([option]) 删除一条数据,option为筛选条件,当有多条数据符合该条件时,只删除第一个查到的,当option为空时默认删除第一条 
// deleteMany([option]) 删除多条数据,option为筛选条件,当options为空时删除该集合所有数据 

// User.deleteMany({name:'zt'})
// .then((data)=>{
//     console.log(data,'删除所有成功')
// })
// .catch((data)=>{
//     console.log(data,'删除所有失败');
// })

// 改
// update(query,update) query为查询条件,update为修改后的数据 如果匹配到多条数据只修改第一条
// updateMany(query,update) 批量修改query为查询条件,update为修改后的数据 
// updateOne(query,update) 与update()相同,只修改匹配到的第一条数据
// User.update({sex:1},{age:90})
// .then((data)=>{
//     console.log(data,'更新成功');
// })
// .catch((data)=>{
//     console.log(data,'更新失败')
// })

// 查
/*
mongodb 条件操作符
$gt >
$lt <
$gte >=
$lte <=
$ne !=
$eq =
模糊搜索
{title:/教/} title中包含教的文档
{title:/^教/} title中以教开头的文档
{title:/教$/} title中以教结尾的文档
*/

//find(query) // 查询符合条件的所有数据 
//findOne() //查询符合条件的第一条数据
//findById() //通过id查找一条数据,该id为mongodb自动生成的id 在查找前会对id进行数据转换
// User.findById("5e70dcf88963670128d1c20e")
// .then((data)=>{
//     console.log(data,'查询成功')
// })
// .catch((data)=>{
//     console.log(data,'查询失败')
// })

使用mongodb + nodeJs实现一个登录注册逻辑

1.项目结构

- server.js   //服务
- db  //数据库管理
  - model 
    - userModel.js //创建userModel对象
  - connect.js  //连接数据库
- router //路由
  - useRouter.js //接口具体逻辑

2.项目需求分析

1.注册

先判断数据库中是否有userName,有则返回账号已存在,注册失败,否则写入数据库,标识注册成功。

2.登录

根据userName 和 password 判断数据库中是否存在该条数据,存在则表示登录成功,否则表示失败。

server.js

const express = require('express');
const db = require('./db/connect');
const app = express();
const userRouter = require('./router/userRouter');
const bodyParser = require('body-parser');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended:false}))

app.use('/user',userRouter);

app.listen(3000,()=>{
    console.log('server start');
})

connect.js

const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/users',{ useNewUrlParser: true,useUnifiedTopology: true });
const db = mongoose.connection;
db.on('error',()=>{
})
db.once('open',()=>{
    console.log('connect ok');
})

userModel.js

const mongoose = require('mongoose');

var userModel = new mongoose.Schema({
    us:{
        type:String,
        default:''
    },
    ps:{
        type:String,
        default:'',
    },
    uid:{
        type:String,
        default:''
    }
})
var user = mongoose.model('users',userModel);
module.exports = user;

userRouter.js

const express = require('express');
const router = express.Router();
const User = require('../db/model/userModel');
router.post('/reg',(req,res)=>{
    let{us,ps} = req.body;
    if(!us || !ps){
        res.send({
            err:-1,
            msg:"参数错误"
        })
    }else{
        User.find({us})
        .then((data)=>{
            if(data.length >= 1){
                res.send({
                    err:-1,
                    msg:"该用户已注册"
                })
            }else{
              return User.insertMany({us,ps,uid:us+ps})
            }
        })
        .then((data)=>{
            if(data){
                res.send({
                    err:0,
                    msg:'注册成功'
                })
            }
            console.log(data,'insert')
        })
        .catch((err)=>{
            res.send({
                err:-1,
                msg:'系统内部错误,请稍后重试'
            })
        })
    }
})
router.post('/login',(req,res)=>{
    let {us,ps} = req.body;
    if(!us || !ps){
        res.send({
            err:-1,
            msg:'参数错误'
        })
    }else{
        User.find({us,ps})
        .then((data)=>{
            console.log(data,'50000');
            if(data){
                res.send({
                    err:0,
                    msg:'注册成功',
                    us:data[0].us,
                    uid:data[0].uid
                })
            }
        })
        .catch((err)=>{
            res.send({
                err:-1,
                msg:'系统内部错误'
            })
        })
    }

})
module.exports = router;

跨域问题

ajax 同源策略 协议 域名 端口号

解决跨域:

app.all("*",function(req,res,next){ //设置允许跨域的域名“*”代表允许所有
    //允许的请求头
    res.header("Access-control-Allow-Origin","*");
    //设置允许的请求方式
    res.header("Access-Control-Allow-Methods","DELETE,PUT,POST,GET,OPTIONS");
    if(req.method.toLowerCase() == 'options'){
        res.send(200)
    }else{
        next();
    }
})

上传图片

npm install multer --save

//后端
var storage = multer.diskStorage({
    destination:function(req,file,cb){
        cb(null,'./uploads'); //定义文件存放地址
    },
    filename:function(req,file,cb){ //定义上传的文件名
        let types = file.originalname.split('.');
        let type = types[types.length - 1]; //取后缀
        cb(null,file.fieldname+'-'+Date.now()+parseInt(Math.random()*9999)+'.'+type);
    }
})


var upload = multer({storage:storage}); //调用

router.post('/imgs',upload.single('keys'),(req,res)=>{  //这个keys 属于约定,前后端都得知道
    const {mimetype,size,filename} = req.file;
    let types = ['jpg','png','jpeg','gif'];
    let imgtype = mimetype.split('/')[1];
    if(size>102400){  //上传大小判断
        res.send({
            err:-1,
            msg:'图片尺寸超过10k'
        });
        return;
    }else if(types.indexOf(imgtype)<=-1){  //文件类型判断
        res.send({
            err:-1,
            msg:"图片类型错误"
        })
        return;
    }else{
        res.send({
            err:0,
            msg:"上传成功",
            url:`/img/${filename}` //上传成功后将地址返回给前端
        })
    }
})

//前端

        $('button').click(function(){
            let formData = new FormData();
            let file = $('#file')[0].files[0];
            formData.append('keys',file);

            $.ajax('http://localhost:3000/upload/imgs',{
                method:'POST',
                cache:false,
                data:formData,
                processData:false,
                contentType:false,
                success:function(data){
                    console.log(data);
                    $('img').attr('src',`http://localhost:3000${data.url}`)
                }
            })

            console.log(file);
        })
上一篇下一篇

猜你喜欢

热点阅读