node服务器开发

137 阅读9分钟
// 导入http模块
const http = require('http')
// 创建web服务器
const server = http.createServer()
//为服务绑定一个request事件
server.on('request', function(req, res){
    //客户端请求地址
    const url = req.url
    // 设置访问某人响应
    let content ='\<h1>404 not found!\</h1>'
    //req.method客户端请求method
    const method = req.method;
    console.log(method, 'debugMethod')
    if(url === '/'){
        content='\<h1>首页\</h1>'
    }
    //防止中文乱码问题
    res.setHeader('Content-Type', 'text/html; charset=utf-8');
    // 响应内容,并结束响应过程
    res.end(content)
})

// 启动服务器 server.listen(8080, ()=>{ console.log('服务启动了。。。。') }) node中的模块作用域

  1. 模块作用域的好处是防止全局污染
  2. moudule对象包含所有信息,moudule.exprots可以共享某块信息
  3. require方法导入某块时,导入的结果永远以module.exports
  4. CommonJs规范是nodejs规范,module代表当前模块,mould.expots是对外接口,使用rqurie()加载模块 npm包是封装出来的
  5. 包共享平台https//wwww.npmjs.com
  6. 共享包https//registry.npmjs.org/
  7. npm i 包名称 cls清空终端
  8. npm i @版本号下载版本号
  9. package.json包管理文件
  10. .gitigore中的文件忽略上传
  11. npm init -y 快速创建package.json
  12. dependencies节点,用来记录npm install命令安装了那些包
  13. npm i 安装多个包时使用空格隔开
  14. npm uninstall卸载包
  15. devDependencies只标记测试环境使用install -i 包名 -D
  16. 检查下班镜像源 npm confing get registry
  17. 切换镜像源 npm config set registry='registry.npm.taobao.org/'(镜像地址)
  18. nrm 镜像包管理工具 npm ls nrm use
  19. 包分类i5ting_toc把md文件转化为html文件

模块加载机制

  1. 如果模块已经在缓存中,将不会再进行加载
  2. 内置加载模块优先级最高
  3. 使用require导入自定义模块时,如果省略扩展名,node会按照确切文件名加载,没有会补全js加载,没有会补全.json,没有会补全node,都没有会直接加载失败
  4. 第三方模块加载机制,加载顺序--->当前文件加载---->然后往上逐一加载

express expressjs.com.cn快速搭建服务器

//导入express
const express = require('express');
//创建服务器
const app = express()
//监听get请求
// app.get('/user', (req,res)=>{
//     //调用express提供的res.send方法,向客户端响应一个JSON对象
//     res.send({name:'zhangsan', age:'28', gender:'男'})
// })
// //监听pos请求
// app.post('/user',(req,res)=>{
//     res.send('请求成功')
//     //调用express提供的res.send方法,向客户端响应一个文本
// })
// app.get('/', (req, res)=>{
//     //通过req.query 响应客户端发送过来的查询参数
//     //默认req.query是个空对象
//    console.log(req.query, 'debug')
//    res.send(req.query)
// })
// app.get('/user/:id',(req, res)=>{
//     //动态匹配导的URL,默认是一个空对象
//     console.log(req.params)
//     res.send(req.params)
// })
//调用express.static()方法提供静态资源,多次调用express.static()只会调用第一个使用
app.use(express.static('./eatWhat'))
//需要访问是需要加个前缀
app.use('/eatWhat' ,express.static('./eatWhat'))
//启动服务器
app.listen(80, ()=>{
    console.log('express server running at http://127.0.0.1')
})

nodemon 自动更新代码是否发生变化npm install -g nodemon

express路由

  1. express中的路由只是的客户端请求和服务器处理函数之间的映射关系
  2. 路由的匹配逻辑是从上往下匹配
  3. 路由中间键是依次处理的顺序,通过next()来实现函数调用
  4. 使用qpp.use()的是全局中间键,不使用app.use()的局部中间键
const app = express()
//定义一个最简单的
const mw = ((req,res, next)=>{
    console.log('这是一个最简单的中间键函数')
    // 全局挂载时间
    const time = Date.now()
    req.startTime =time
    //把流转关系转交给下一个中间键或路
    next()
})
//将mw注册成全局中间键
app.use(mw)
app.get('/',(req,res)=>{
    res.send('hello world!')
})
app.post('/',(req,res)=>{
    res.send('Post hello world!')
})
app.listen(80 ,()=>{
    console.log('http://127.0.0.1');
})

局部

const express = require('express')
const app = express();
const mw = (req,res , next)=>{
    console.log('局部生效中间键')
    next()
}
//
app.get('/user',mw,(req, res)=>{
    res.send('hello user get')
})
app.post('/name',(req, res)=>{
    res.send('hello user post')
})

app.listen(80,()=>{
    console.log('http://127.0.0.1')
})
  1. 多个局部中间键使用逗号隔开从左往右执行,一定在路由之前注册中间键,最后需要使用next()
  2. 绑定在app实例上的都是应用级别
  3. express.router绑定在router身上的中间键都是路由级别的中间键
  4. 错误级别的中间键必须有4个参数
const express = require('express')
const app = express()

app.get('/usr',(req,res)=>{
    //抛出错误
    throw new Error('服务发生内部错误')

    res.send('Home page')
})
//注册错误中间键
app.use((err,req,res,next)=>{
    console.log(err.message + '错误信息')
    res.send('err:' + err.message)
    next()
})
app.listen(80,(req, res)=>{
    console.log('http://127.0.0.1/');
})
  1. app.use(express.json())解析JSON数据
  2. app.use(express.urlenCoded({extended: flase}))
const express = require('express')
const app = express();
//Json数据机械除错误中间键其余都需要路由前配置
app.use(express.json())
//解析urlencoded数据
app.use(express.urlencoded({extends: false}))
app.post('/name',(req, res)=>{
    // 获取前端数据
    console.log(req.body)
    res.send('hello user post')
})

app.listen(80,()=>{
    console.log('http://127.0.0.1')
})
  1. 使用第三方定义中间键
const express = require('express');
const app = express()
app.post('/user',(req,res)=>{
    console.log(req.body)
    res.send('hello post')
})
//导入第三方body-parser
const parser = require('body-parser')
app.use(parser.urlencoded({extended: false}))
app.listen(80,()=>{
    console.log('http://127.0.0.1')
})

  1. 自定义中间捷
const express = require('express')
const app = express();
//导入querystring模块
const qs = require('querystring')
//定义全局中间键
const mv = (req,res,next)=>{
    //定义存储客户端发送请求数据
    let str ='';
    // 监听req的data事件
    req.on('data',(chunk)=>{
        str +=chunk
    })
    //监听end事件
    req.on('end', ()=>{
        // 在str中存储完整的请求体数据
        console.log(str)
        //把字符串请求体数据解析成对象格式
        const body = qs.parse(str)
        console.log(body)
        req.body= body
        next()

    })
   
}

app.use(mv)
app.post('/name',(req, res)=>{
    res.send(req.body)
})

app.listen(80,()=>{
    console.log('http://127.0.0.1')
})
  1. 使用node服务对外api接口
const app = express();
app.use(express.json())
app.use(express.urlencoded({extends: false}))
//导入路由
const router = require('./router/router');

//注册路由到app上
app.use('/api', router)

app.listen(80,()=>{
    console.log('http://127.0.0.1')
})

封装路由

const express = require('express');
//创建一个路由模块
const router = express.Router();
//挂载具体路由
router.get('/get', (req, res)=>{
    console.log('deebug');
   //通过客户端查询发送服务器数据
   const query = req.query
   //调用res.send()方法,向客户端发送
   res.send({
    status: 0, //0表示数据处理成功
    mag: 'GET 数据请求成功',
    data: query //响应客户端数据
   })
})
//挂载具体路由
router.post('/post', (req, res)=>{
   //通过客户端查询发送服务器数据
   const body = req.body
   //调用res.send()方法,向客户端发送
   res.send({
    status: 0, //0表示数据处理成功
    mag: 'Post 数据请求成功',
    data: body //响应客户端数据
   })
})

//导出路由
module.exports = router

解决api接口跨域问题

  1. cors主流解决方案 npm i cors
const express = require('express')
const app = express()
//导出cors中间键
const cors = require('cors');
//配置cors中间键
app.use(cors)
app.listen(80,()=>{
    console.log('http://127.0.0.1')
})
只允许某一个跨域共享access-control-allow-oringin配置

2. jsonp只支持get解决

//JSONP定义接口并实现
use.get('/api/jsonp',(req,res)=>{
    //获得函数
    const funName = req.query.callback
    //定义向客户端发送数据对象
    const data = {name:'zs', age:19,}
    //拼接函数调用
    const scriptStr = `${funName}(${JSON.stringify(data)})`
    res.send(scriptStr);
})

MySQL数据库

  • select * from my_db_node.users limit 10
  1. 增加数据
  • insert into users (username, passworld, status) values ('aww','789',1)
  • update users set status=1 ,passworld='567' where username='zs'
  1. 删除
  • delete from users where id=2
  1. and和or
  • select * from my_db_node.users where status='0' and id<3
  • select * from my_db_node.users where status='0' or id=3
  1. 升序
  • select * from users order by id
  1. 降序
  • select * from users order by id desc
  1. 多重排序
  • select * from users order by id desc, username asc
  1. count 和 as的作用统计和另取名
  • select count(username) as uv from users

node操作MySQL 链接数据库

const mysql = require('mysql')

//创建mysql链接
const db = mysql.createPool({
    host: '127.0.0.1',//数据库存放地址
    user: 'root', //登录数据库账号
    password: 'admin123', //登录密码
    database: 'my_db_node' //操作数据
})
  1. 检测数据库是否成功
//检查数据是否链接
db.query('select 1', (err, results)=>{
    //错误返回
    if(err) return console.log(err.message);
    //成功执行
    console.log(results)

})
  1. 查询数据
//调用数据库
const sqlSelect = 'select * from users'
db.query(sqlSelect, (err, results)=>{
    //错误返回
    if(err) return console.log(err.message);
    //成功执行,结果返回为数组
    console.log(results)

})
  1. 数据插入
//新增数据
const user = {username: 'zz', password: 'main123'}
const sqlAdd = 'insert into users(username, passworld) values(?,?)'
//执行sql
db.query(sqlAdd,[user.username, user.password],(err, results)=>{
    // 数据插入失败执行结果
    if(err) return console.log(err.message);
    //数据插入成功返回是对象,可以通过affectedRows判断是否成功
    if(results.affectedRows ===1){
        console.log('数据插入成功');
    }
})
  • 便捷写法
//新增数据
const user = {username: 'zzj', passworld: 'main123'}
// const sqlAdd = 'insert into users(username, passworld) values(?,?)'
//简化写法
const sqlAdd= 'insert into users set ?'
//执行sql
db.query(sqlAdd, user ,(err, results)=>{
    // 数据插入失败执行结果
    if(err) return console.log(err.message);
    //数据插入成功返回是对象,可以通过affectedRows判断是否成功
    if(results.affectedRows ===1){
        console.log('数据插入成功');
    }
})
  1. 数据更新
const user = { status: 1, passworld: '7123', username: 'zzj'}
const updatas = 'update users set status=? ,passworld=? where username=?'
db.query(updatas, [user.status, user.passworld, user.username ],(err, results)=>{
    console.log('111')
    if(err) return console.log(err.message);
    //数据插入成功返回是对象,可以通过affectedRows判断是否成功
    if(results.affectedRows ===1){
        console.log('数据更新成功');
    }
})
  • 便捷方式
const user = { status: 0, passworld: '711', username: 'zzj'}
const updatas = 'update users set ? where username=?'
db.query(updatas, [user, user.username ],(err, results)=>{
    console.log('22')
    if(err) return console.log(err.message);
    //数据插入成功返回是对象,可以通过affectedRows判断是否成功
    if(results.affectedRows ===1){
        console.log('数据更新成功');
    }
})
  1. 删除数据,生成环境中不建议删除数据
//删除数据
const user = { status: 0, passworld: '711', username: 'zzj'}
const sqlDelete = 'delete from users where username=?'
db.query(sqlDelete, [user.username ],(err, results)=>{
    if(err) return console.log(err.message);
    //数据插入成功返回是对象,可以通过affectedRows判断是否成功
    if(results.affectedRows ===1){
        console.log('数据删除成功');
    }
})

web前端的身份认证

  1. session认证,一般在服务端验证,由后端发送终端,一般不超过4kB的cookie,cookie的特性自动发送,域名独立,过期时限,4k限制,cookie不具有安全性,需要session认证
  2. JWT最常见的认证机制,组成有三部分Heade/payload/signatuer,放在authization 项目中使用session

npm i express-session

  1. 配置session
const express = require('express')
const app = express()
//创建服务器session
const session = require('express-session');
//配置session
app.use(session({
    secret:'item',
    resave: false,
    saveUninitialized: true,
}))

app.listen(80,()=>{
    console.log('https://127.0.0.1')
})

验证是否登录

// 判断用户是否登录
app.post('/login',(req, res)=>{
    req.session.user = req.body //用户信息
    req.session.islogin = true //用户登录状态
    res.send({status:0, msg: '登录成功'})

})

// 判断用户是否登录
app.get('/login/name',(req, res)=>{
   if(!req.session.islogin){
    return res.send({status:1 , msg: 'fail'})
}
 res.send({
    status: 0,
    msg: 'success',
    username: req.session.user.username
 })
})

用户清空session

//判断用户是否清空session
app.post('/login/out',(req, res)=>{
    //清空登录方法
    req.session.destroy()
    res.send({status:0, msg: '退出登录成功'})
})

生成token

app.post('/username', (req, res)=>{
    //将前端数据传递到userinfo
    const userinfo = req.body
    //登录失败
    if(userinfo.username !== 'admin' || userinfo.password !== '000000'){
        return res.send({
            status: 400,
            message: '登录失败'
        })
    }
    //登录成功调用jwt方法
    //配置对象秘钥,配置token有效期
    const tokenStr = jwt.sign({username: userinfo.username}, secretKey, {expiresIn:'80s'})
    //登录成功
    res.send({
        status:200,
        massage: '登录成功',
        token: tokenStr, //给客户端发送请求
    })
})
  1. JWT最常见的认证机制校验token
const express = require('express')
//导入jsWeb
const Jwt = require('jsonwebtoken');
//导入jwt
const expressJwt = require('express-jwt')
const app = express()
//定义想秘钥
const secretKey = 'luckyJian'
//注册解析还原中间键,unless设置是否需要访问权限
app.use(expressJwt({secret: secretKey}).unless({path: [/^\/api\//]}))
app.post('/api/username', (req, res)=>{
    //将前端数据传递到userinfo
    const userinfo = req.body
    //登录失败
    if(userinfo.username !== 'admin' || userinfo.password !== '000000'){
        return res.send({
            status: 400,
            message: '登录失败'
        })
    }
    //登录成功调用jwt方法
    //配置对象秘钥,配置token有效期
    const tokenStr = Jwt.sign({username: userinfo.username}, secretKey, {expiresIn:'80s'})
    //登录成功
    res.send({
        status:200,
        massage: '登录成功',
        token: tokenStr, //给客户端发送请求
    })
})
// 验证是否登陆成功
app.get('admin/user',(req,res)=>{
    console.log(req.user)
    res.send({
        status: 200,
        message: '用户信息获取成功',
        data: req.user
    })
})
// 捕获错误
app.use((err,req,res,next)=>{
    if(err.name === 'UnauthorizedError'){
      return  res.send({
        status: 401,
        massage: '无效token'
    })
    }
    res.send({status:500,
    massage: '未知错误'
})
})
app.listen(80,()=>{
    console.log('https://127.0.0.1')
})