node学习

467 阅读8分钟

使用Node运行JS代码

  • 使用命令行敲击命令

image.png

  • 使用node.exe运行(找到文件件,node xxx.js即可)

image.png

退出正在运行程序:ctrl+C两次

浏览器中的js是否可以读写到电脑上的文件:不可以,否则很危险,浏览器端的js最高只能访问到当前的浏览器

Node.js不是浏览器端的js:服务器端的js,可以独立于浏览器运行

使用内置模块fs读取txt文件内容

遇到问题,运行时console的中文在命令板上都是乱码
解决方案:将txt的内容重新使用utf-8的格式打开。就是格式需要统一,fs解析的格式和文本的格式需要一致;

image.png

路径问题

获取绝对路径

  • __dirname:文件夹的绝对路径
  • __firename: 文件的绝对路径
const path = require("path");
// 生成路径
const path1 = path.join(__dirname, "./01.txt")
console.log(path1);

使用node开启http服务器

const http = require('http')

const hostname = '127.0.0.1'
const port = 3000

// 开启了服务器
const server = http.createServer((req, res) => {
  res.statusCode = 200
  res.setHeader('Content-Type', 'text/plain')
  res.end('Hello')
})

server.listen(port, hostname, () => {
  console.log(`Server running at http://${hostname}:${port}/`)
})

使用第三方模块nodemon

  • 可以使用 nodemon xxx.js代替 node xxx.js
  • 作用:检测xxx.js是否修改,修改了自动运行(不需要再重启了)

server的req和res

  • req:获取浏览器发送的东西,比如req.url;req.method(请求方式);
  • res:响应的内容:如果要给浏览器设置通过res即可,比如:
  // 状态码
  res.statusCode = 200
  // 设置响应头
  res.setHeader('Content-Type', 'text/plain;charset=utf8')
  // 返回响应报文 已经返回了

设置响应头格式

    //设置响应头,告诉浏览器内容的格式Content-Type text/plain 普通文本
       res.setHeader('Content-Type', 'text/plain;charset=utf8');
   //设置响应头,告诉浏览器内容的格式Content-Type text/html html文本
       res.setHeader('Content-Type', 'text/html;charset=utf8');

注意:

  • 浏览器的嗅探功能
    • 服务器不告诉类型浏览器会自动尝试解析,
    • 很多时候可以解析出来
  • 对于非文本类的文件,读取时,别设置编码格式
    • 设置之后解析不出来了

npm 项目初始化

# 自己输入信息,如果没有什么要输入的,比较累赘
npm init 
# 自动生成信息
npm init -y
{
   名字
  "name": "03.npmuse",
   版本
  "version": "1.0.0",
  描述
  "description": "",
  主要文件
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  关键字
  "keywords": [],
  作者
  "author": "",
  开源协议
  "license": "ISC"
}

注意:使用npm init -y ,文件夹不能使用中文

文件说明:

  • package.json

    • 保存项目的基本信息....
    • 下载的第三方模块的名字和版本
  • package-lock.json

    • 使用npm下载第三方模块时自动生成的文件
    • 保存模块信息
    • 模块的下载地址,下次下载速度就会很快
  • node_modules

    • 下载的第三方模块放置的路径
    • 不要轻易的删除
    • 每个模块(包)的文件夹中,有这个模块的所有信息:版本信息,说明,测试代码,实例代码等等.....
    • 如非必要不要去动里面的文件
    • 也不需要担心会把你电脑撑坏

cnpm

www.npmmirror.com/?spm=a2c6h.…

npm install -g cnpm --registry=https://registry.npmmirror.com

注意

  • 不会生成package-lock.json,只有npm才会生成
  • cnpm i xxx不会把模块信息(包信息)保存到package.json
    • 完整的命令是cnpm i xxx --save

express

中文网:www.expressjs.com.cn/

注意:

  • express是一个框架
  • 内部整合了很多第三方的模块
  • 下载express的时候npmcnpm自动的读取他需要使用的其他模块,并一起下载
  • 保证express一定可以运行
const express = require('express')
const app = express()
const port = 3000

app.get('/', (req, res) => {
  res.send('Hello World!')
})

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`)
})

三大核心功能:

  • 静态资源托管

暴露静态文件:

// 暴露public让外部可以访问
app.use(express.static('public'))
app.get('/', function (req, res) {
  res.send('Hello World!')
})

app.post('/', function (req, res) {
  res.send('Got a POST request')
})

app.put('/user', function (req, res) {
  res.send('Got a PUT request at /user')
})

app.delete('/user', function (req, res) {
  res.send('Got a DELETE request at /user')
})

express.Router的用法:将路由进行拆分

使用页面

const express = require('express')
// 导入路由
const dog = require('./router/dog')
// 创建服务器对象
const app = express()

// 定义端口
const port = 3000
// 注册路由到app中
app.use('/dog',dog)
// 开启监听
app.listen(port,()=>{
    console.log(`路由已启动,端口为${port}`);
})

路由页面

// 创建路由
const express = require('express')
// 创建路由
const router = express.Router()
// 通过router注册路由
router.get('/',(req,res)=>{
    res.send('11111')
})
router.get('/info',(req,res)=>{
    res.send('2222')
})
// 暴露出去
module.exports  = router

image.png

  • 中间件

www.expressjs.com.cn/resources/m…

body-parser

  • 下包:
npm i body-parser
  • 导包
 `const bodyParser = require('body-parser')`
  • 使用
`app.use(bodyParser.urlencoded({ extended: false }))`

实例:

var express = require('express')
var bodyParser = require('body-parser')

var app = express()
const port = 3000 
// 解析通过 application/x-www-form-urlencoded 提交的数据
app.use(bodyParser.urlencoded({ extended: false }))

// parse application/json
// app.use(bodyParser.json())
app.post('/test',(req,res)=>{
  console.log(req);
  res.send(req.body)
})


app.listen(port, () => {
    console.log(`Example app listening on port ${port}`)
})

注意:

  • 中间件

    • body-parser可以理解为express插件,让express额外增加功能
    • 中间件,也是node的第三方模块,只不过必须要和express结合到一起使用
    • body-parser是一个特殊的第三方模块
  • 请求的方法

    • postman左侧的请求方法一定要和注册路由的方法对应
  • 请求的地址

    • 自己测试时,建议使用:localhost或者127.0.0.1
    • 上一步没问题了,在测试局域网ip
  • req.body中的属性

    • body对象的属性取决于我们调用接口时,发送的数据

终端工具 cmder

官网

cmder在多窗口管理这块更加便捷,

URL内置模块

Node中文网 - url模块

decodeURI方法

基本结构:

// 导入 http
const http = require('http')
// 导入 fs
const fs = require('fs')
// 导入 path
const path = require('path')

// 端口
const port = 8848

// 创建服务器对象
const server = http.createServer((req, res) => {})

// 开启监听
server.listen(port, () => {
  console.log('服务已启动!!')
})

使用:

// 导入 http
const http = require('http')
// 导入 fs
const fs = require('fs')
// 导入 path
const path = require('path')
// 导入 url
const url = require('url')

// 端口
const port = 8848

// 创建服务器对象
const server = http.createServer((req, res) => {
  // 获取url
  let reqUrl = req.url
  // 转码
  reqUrl = decodeURI(reqUrl)
  // 使用url模块解析参数
  const queryObj = url.parse(reqUrl, true)
  // 通过上一步获取的对象中的query,点出你要的值
  const key = queryObj.query.key
  const haha = queryObj.query.haha
  //   console.log(queryObj)
  //   console.log(reqUrl)
  // 返回地址
  res.end(reqUrl)
})

// 开启监听
server.listen(port, () => {
  console.log('服务已启动!!')
})

原生获取post提交的数据

Node.js - http.createserver

Node.js - querystring

// 导入 http
const http = require('http')
// 导入 fs
const fs = require('fs')
// 导入 path
const path = require('path')
const querystring = require('querystring')

// 端口
const port = 8848

// 创建服务器对象
const server = http.createServer((req, res) => {
  // 定义保存数据的变量
  let str = ''
  // data回调函数 数据传输时触发
  req.on('data', chunk => {
    // console.log(chunk)
    str += chunk
  })
  // end 回调函数 数据传输完毕时触发
  req.on('end', () => {
    console.log('传递完毕')
    console.log('str:', decodeURI(str))
    // 解析数据
    const sendData = querystring.parse(decodeURI(str))
    console.log('解析之后的值:', sendData)
    res.end('数据传递完毕')
  })
})

// 开启监听
server.listen(port, () => {
  console.log('服务已启动!!')
})

express(中间件)获取上传的文件

express-fileupload

  • 下包 npm i express express-fileupload --save
// 导入 express 第三方模块
const express = require('express')

// 导入 path 内置模块
const path = require('path')
// 导入文件上传模块
const fileUpload = require('express-fileupload')

// 创建服务器对象
const app = express()
// 端口
const port = 3000

// 注册文件上传中间件
app.use(fileUpload())

// 文件上传接口
app.post('/upload', (req, res) => {
  //   console.log(req.files)
  //   res.send('success')
  // 移动图标
  const iconFile = req.files.icon
  // 全路径
  const fullPath = path.join(__dirname, `./uploads/${iconFile.name}`)
  // 移动
  iconFile.mv(fullPath, err => {
    if (err) {
      return res.send('服务器内部错误')
    }
    res.send('文件上传成功')
  })
})

// 开启监听
app.listen(port, () => console.log(`示例程序已启动,端口为 ${port}!`))

默认上传的文件外部是无法访问的,咱们需要通过静态资源暴露出去哦


//一:
// 提供静态资源访问功能 把uploads文件夹暴露出去让大伙访问
// 使用类似于这样的地址访问  http://IP地址:3000/0.gif 直接访问到uploads文件夹里的内容
app.use(express.static('uploads'))

二 如果希望访问时增加路径名,可以添加第一个参数
// 参数1 自己起的文件夹名
// 就可以用类似于这样的方式访问了http://IP地址:3000/uploads/0.gif
app.use('/uploads', express.static('uploads'))
// 就可以用类似于这样的方式访问了http://IP地址:3000/static/0.gif
app.use('/static', express.static('uploads'))

node设置cors解决跨域

  • 原生
// 导入 express
const express = require('express')
// 定义端口
const port = 8848
// 创建服务器对象
const app = express()

// 随机数
app.get('/randomNum', (req, res) => {
  // 返回
  res.send(Math.ceil(Math.random() * 100))
})

// 开启监听
app.listen(port, () => {
  console.log(`服务已启动:端口为${port}`)
})
  • express
// 导入 express
const express = require('express')
//导入cors
const cors = require('cors')
//使用cors
app.use(cors())
// 定义端口
const port = 8848
// 创建服务器对象
const app = express()
// 开启监听
app.listen(port, () => {
  console.log(`服务已启动:端口为${port}`)
})

使用步骤:

  • 下包
cnpm i cors --save
  • 导包
const cors = require('cors')
  • 用包
app.use(cors())

node设置JSONP解决跨域

  • 服务器端原生实现JSONP 主要干两件事:
    • 接收callback的参数
    • 返回一个函数的调用给浏览器

// 返回一个对象
// 浏览器端必须通过get请求 参数名callback提交一个函数名
// 返回一个函数的调用回去,并且传递一个 对象 作为参数
app.get('/randomFood', (req, res) => {
  // get请求参数获取 callback 比如 doSomething
  const { callback } = req.query

  // 返回一个 函数调用 函数名({name:"jack",age:18,skill:"jump"})
  // 返回的是doSomething({name:"西兰花炒蛋",color:"又黄又绿",price:10})
  res.send(`${callback}({name:"西兰花炒蛋",color:"又黄又绿",price:10})`)
})
  • express实现JSONP
// express的jsonp方法来简化编码
// get提交 callback
// 返回一个函数的调用,有参数
app.get('/randomFoodPro', (req, res) => {
  res.jsonp({
    name: '',
    color: '',
    price: 20
  })
})
// JSONP
$('.jsonp').click(function () {
  $.ajax({
    url: 'http://IP地址:端口号/search',
    type: 'get',
    // 设置使用JSONP请求
    dataType: 'jsonp',
    success(backData) {
      console.log(backData)
    },
  })
})

注意

  • jQuery的JSONP只需要设置dataTypejsonp即可
  • 本质还是通过script标签发送了一个跨域请求,携带了callback去服务器
    • jQueryJSONPajax有没有关系?
      • 没有

mySQL简单学习

建表语句

CREATE TABLE `user` (
  `Id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(255) DEFAULT NULL COMMENT '用户名',
  `password` varchar(255) DEFAULT NULL COMMENT '密码',
  PRIMARY KEY (`Id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='用户表';

新增语句

insert into 表名(字段名,字段名2) values(值,值2);

删除语句

-- 删除
delete from 表名
-- 带条件的删除
delete from 表名 where 条件

修改语句

-- 改一个
update 表名 set 字段 = 新值;
-- 改多个
update 表名 set 字段 = 新值 ,字段2 = 新值2;
-- 带条件修改
update 表名 set 字段 = 新值 ,字段2 = 新值2 where 条件

查询语句

-- 查询指定字段
select 字段 from 表名;
-- 查询所有字段
select * from 表名;
-- 带条件查询所有字段
select * from 表名 where 条件;

注释

-- 注释
/*
    多行注释
*/

通配符-->模糊查询

%为通配符,一般搭配 like 关键字使用。

  • 查询所有 字段关键字 开头的数据
select * from 表名 where 字段 like '关键字%'; 
-- 查询user表中name以j开头的所有数据
select *from student where name like 'j%';
  • 查询所有 字段关键字 结尾的数据
select * from 表名 where 字段 like '%关键字'; 
-- 查询student表中name以y结尾的所有数据
select *from student where name like '%y';
  • 查询所有 字段 包含 关键字 的数据
select * from 表名 where 字段 like '%关键字%'; 
-- 查询student表中name中包含o的所有数据
select *from student where name like '%o%';

并且条件

  • 使用and关键字
-- 查询student表中name为jack,并且age为20的数据
select *from student where name='jack' and age='20'

或者条件

  • 使用or关键字
-- 找到student表中age小于10,或者age大于100的数据
select *from student where age < 10 or age > 100;

连表查询

  • 很多时候同一个页面的数据是从多张表取出
  • 例如:如果想展示所有用户的信息以及它下的订单商品,就需要找到两张表的数据联合起来。
select 字段 from1 inner join2 on 对应关系
-- 找到customer和horder双表结合的结果,只把customer中的cId字段和horder表中custormId字段相等的记录组合在一起
select *from customer inner join horder on customer.cId =  horder.custormId

分页查询

  • 有时候某张表里有大量数据,而我们只需要查中间的某几条,因此可以用下面的分页查询语句
select * from 表名 limit 第几条开始,查几条;
-- 查询student表里第10条到第20条数据(一共查出来10条)
select * from student limit 10,10;

代码使用mysql

npm-mysql模块

  • 下包 :npm i mysql --save
  • 官方用例
//导包
var mysql      = require('mysql');
//创建数据库
var connection = mysql.createConnection({
  host     : 'localhost',
  user     : 'me',
  password : 'secret',
  database : 'my_db'
});
 //连接数据库
connection.connect();
 //执行sql语句
connection.query('SELECT 1 + 1 AS solution', function (error, results, fields) {
  if (error) throw error;
  console.log('The solution is: ', results[0].solution);
});
 //链接断开
connection.end();

注意:

  1. 增删改查的操作,方法都是一样的,不同的是SQL
  2. 增删改返回的是受影响的行数
  3. 查询返回的是数据,无论有没有都是数组

knex模块

更简单的操纵数据库 npm - knex

  • 下包:npm i knex mysql --save
  • 使用
const knex = require('knex')({
  client: 'mysql',
  connection: {
    host : '127.0.0.1',
    user : 'your_database_user',
    password : 'your_database_password',
    database : 'myapp_test'
  }
});
  • 调用
//具体看官网语法
knex('表名').select().where()
.then(res=>{})

node.js的模块化

拓展阅读 - 阮一峰模块化01

拓展阅读 - 阮一峰模块化02

commonjs官网 规定了模块的导入语法

const xx = require('xxx')

模块的暴露语法

module.exports=基本数据类型
module.exports=复杂数据类型

image.png

实现express中间件

基础模板

// 导入express
const express = require('express')
// 创建服务器对象
const app = express()

// 设置端口
const port = 4399

// 开启监听
app.listen(port, () => {
  console.log(`中间件测试demo已启动,端口为${port}`)
})

  • 中间件就是一个回调函数

  • 参数有3个

    • req:请求
    • res:响应
    • next:下一个中间件(回调函数)
  • 中间件共享同一个请求对象和响应对象

app.use((req, res, next) => {
  console.log(' 回调函数1 执行啦!!')
  req.secret = '我有一个小秘密,就不告诉你 嘿!'
  req.body = {
    name: 'jack',
    age: 18
  }
  req.files = {
    icon: '班长的图片'
  }
  // 直接阻断后续执行
  return res.send({
    msg: '小老弟,怎么回事',
    message: '天天GHS'
  })
  // 通过CORS设置所有的来源都允许跨域访问
  //   res.setHeader('Access-Control-Allow-Origin', '*')
  // 中间件如果不响应请求,或者不执行next
  next()
})
app.use((req, res, next) => {
  console.log(' 回调函数2 执行啦!!')
  req.message = '我是一条小青龙,小青龙'
  // 中间件如果不响应请求,或者不执行next
  next()
})

// 注册路由
app.get('/list', (req, res) => {
  console.log('req.secret', req.secret)
  console.log('req.message', req.message)
  console.log(req.body)
  console.log(req.files)
  res.send({
    data: ['西瓜', '南瓜', '冬瓜', '北瓜'],
    msg: '获取成功'
  })
})

// 开启监听
app.listen(port, () => {
  console.log(`中间件测试demo已启动,端口为${port}`)
})

image.png

第三方的中间件内部就是req中添加了属性

比如req.body,req.files

  • 中间件就是回调函数
  • 共享
    • req
    • res
  • 通过next去到下一个回调函数(中间件)
    • req.setHeader
    • res.send
  • 动态的为req添加属性
    • body-parser就是为req加了body
    • express-fileupload就是为req加了files

实现一个cors中间件

// 暴露一个回调函数即可
module.exports = (req, res, next) => {
  console.log('设置了允许的 header')
  // 设置允许的头
  // 通过CORS设置所有的来源都允许跨域访问
  res.setHeader('Access-Control-Allow-Origin', '*')
  // 继续向后执行
  next()
}

使用页面

const cors = require('./cors')//为具体路径
app.use(cors)

验证码的刷新功能在html怎么调用

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <img src="http://127.0.0.1:8848/user/captcha" alt="" />
    <script src="./node_modules/jquery/dist/jquery.min.js"></script>
    <script>
      $(function () {
        $('img').click(function () {
          console.log('你点了我!!')
          // img的src如果两次设置的一样,认为图片没有更改
          // 直接使用缓存中的
          // 解决方案,让浏览器认为他变了
          // 末尾添加随机数或者时间戳,让两次的地址不同
          // 通过?进行分割
          //   $(this).attr('src', 'http://127.0.0.1:8848/user/captcha')
          // 从1970年年初至今的毫秒数

          // 时间戳 两次点击肯定不同,并且只会越来越大
          //   console.log(Date.now())
          //   $(this).attr(
          //     'src',
          //     `http://127.0.0.1:8848/user/captcha?${Date.now()}`
          //   )

          // 随机数 两次随机相同的概率非常低
          $(this).attr(
            'src',
            `http://127.0.0.1:8848/user/captcha?${Math.random()}`
          )
        })
      })
    </script>
  </body>
</html>

其他链接

密码

npm-md5

密码强度正则

验证码

svg-captcha