Node.js基础(二)--内置模块

1.url

为了方便观察,我们这里使用log4js第三方库来进行日志输入,而不是console.log,详情可以查看官网教程

npm i log4js -D

const log4js  = require('log4js')

log4js.configure({
    appenders: { cheese: { type: "file", filename: "cheese.log" } },
    categories: { default: { appenders: ["cheese"], level: "error" } },
});

var logger = log4js.getLogger('cheese');

logger.level = "debug";

logger.debug('Hello world')

日志输入会在同级目录下的cheese.log文件中,然后在此基础上我们讲解一下url内置模块的作用

app.js

// 导入url模块
const url = require('url')
const log4js = require('log4js')

log4js.configure({
    appenders: { cheese: { type: "file", filename: "cheese.log" } },
    categories: { default: { appenders: ["cheese"], level: "error" } },
});

var logger = log4js.getLogger('cheese');

const urlString = 'http://www.baidu.com:443/path/index.html?id=2#tag=3'

logger.level = "debug";
//parse解析路径
logger.debug(url.parse(urlString));

const urlObj = {
    protocol: 'http:',
    slashes: true,
    auth: null,
    host: 'www.baidu.com:443',
    port: '443',
    hostname: 'www.baidu.com',
    hash: '#tag=3',
    search: '?id=2',
    query: 'id=2',
    pathname: '/path/index.html',
    path: '/path/index.html?id=2',
    href: 'http://www.baidu.com:443/path/index.html?id=2#tag=3'
}
//format逆向解析
logger.debug(url.format(urlObj))

//resolve进行解析 ../表示返回上一级
logger.debug(url.resolve('http://www.abc.com/a', '../'))
// /b表示从根路径开始找到b文件夹
logger.debug(url.resolve('http://www.abc.com/a', '/b'))

//URLSearchParam类获取参数
const urlParams = new URLSearchParams(url.parse(urlString).search)

logger.debug(urlParams)

logger.debug(urlParams.get('id'))

1.parse

url.parse(urlString[, parseQueryString[, slashesDenoteHost]])

const url = require('url')
const urlString = 'https://www.baidu.com:443/ad/index.html?id=8&name=mouse#tag=110'
const parsedStr = url.parse(urlString)
console.log(parsedStr)

2.format

url.format(urlObject)

const url = require('url')
const urlObject = {
  protocol: 'https:',
  slashes: true,
  auth: null,
  host: 'www.baidu.com:443',
  port: '443',
  hostname: 'www.baidu.com',
  hash: '#tag=110',
  search: '?id=8&name=mouse',
  query: { id: '8', name: 'mouse' },
  pathname: '/ad/index.html',
  path: '/ad/index.html?id=8&name=mouse',
  href: 'https://www.baidu.com:443/ad/index.html?id=8&name=mouse#tag=110'
}
const parsedObj = url.format(urlObject)
console.log(parsedObj)

3.resolve

url.resolve(from, to)

const url = require('url')
var a = url.resolve('/one/two/three', 'four')
var b = url.resolve('http://example.com/', '/one')
var c = url.resolve('http://example.com/one', '/two')
console.log(a + "," + b + "," + c)

2.querystring

在这里我们使用log4js采用自己封装的工具

log.js

const log4js = require('log4js')

log4js.configure({
    appenders: { cheese: { type: "file", filename: "cheese.log" } },
    categories: { default: { appenders: ["cheese"], level: "error" } },
});

var logger = log4js.getLogger('cheese');

logger.level = "debug";

// logger.debug('Hello world')
module.exports = logger

然后这一段我也是一脸懵逼,千锋课程删除了前面大部分,只留下了这些代码,额,参照官网看一下吧…不过好在这是一个过时方法。

app.js

const logger = require('../utils/log')

const querystring = require('querystring')

const query = 'id=2&name=tongyi&from=北京'
const query2 = 'id:2&name:tongyi&from:北京'
const queryEscape = 'id%3D2%26name%3Dtongyi%26from%3D%E5%8C%97%E4%BA%AC'
const queryObj = { id: '2', name: 'tongyi', from: '北京' }

logger.debug(querystring.parse(query))
logger.debug(querystring.escape(query))
logger.debug(querystring.unescape(queryEscape))
logger.debug(querystring.stringify(queryObj, ':', '/'))
logger.debug(querystring.parse(query2, '/', ':'))

const newQuery = querystring.stringify(queryObj, null, null, {
    encodeURIComponent(string) {
        //unescape解码操作,默认将我们的中文字符转换为querystring之后会变成unicode编码
        return querystring.unescape(string)
    }
})

logger.debug(newQuery)

  • node:querystring模块提供了用于解析和格式化 URL 查询字符串的实用程序。可以使用以下方式访问它:
const querystring = require('node:querystring');

querystringAPI 被视为旧版。虽然它仍在维护,但新代码应该使用<URLSraechParams> API。

1.parse

querystring.parse(str[, sep[, eq[, options]]])

const querystring = require('querystring')
var qs = 'x=3&y=4'
var parsed = querystring.parse(qs)
console.log(parsed)

2.stringify

querystring.stringify(obj[, sep[, eq[, options]]])

const querystring = require('querystring')
var qo = {
  x: 3,
  y: 4
}
var parsed = querystring.stringify(qo)
console.log(parsed)

3.escape/unescape

querystring.escape(str)

const querystring = require('querystring')
var str = 'id=3&city=北京&url=https://www.baidu.com'
var escaped = querystring.escape(str)
console.log(escaped)

querystring.unescape(str)

const querystring = require('querystring')
var str = 'id%3D3%26city%3D%E5%8C%97%E4%BA%AC%26url%3Dhttps%3A%2F%2Fwww.baidu.com'
var unescaped = querystring.unescape(str)
console.log(unescaped)

3.http(s)

server.js

const http = require('http')
const logger = require('../utils/log')

//创建一个服务器
//参数为一个回调函数,说明这是一个高阶函数
const server = http.createServer((request, response) => {
    logger.debug(request)
    logger.debug(response)
})

//服务器的监听窗口
server.listen(8080, () => {
    console.log('server at http://localhost:8080...')
})


1.开启调试模式

node --inspect server.js

  • 在浏览器窗口输入:chrmoe://inspect/#/devices,不同浏览器前缀可能不一样,比如说360浏览器是se开头,这里使用谷歌浏览器

在这里插入图片描述

  • 点击左上角绿色的node.js图标计入调试界面

在这里插入图片描述

  • 如果您的浏览器没有进行连接跳转而是出现以下界面:

在这里插入图片描述

  • 则需要自己添加网络连接

在这里插入图片描述

  • 然后切换到控制台进行调试

  • 打断点调试(目的是查看当前所有信息)

node --inspect --inspect-brk server.js

在这里插入图片描述

2.Node进程管理工具

  • supervisor
  • nodemon
  • forever
  • pm2

nodemon的使用:

nodemon server.js

  • 作用:保存后可以直接在浏览器运行,不用每次退出后重启服务器
const http = require('http')
const logger = require('../utils/log')

//创建一个服务器
//参数为一个回调函数,说明这是一个高阶函数
const server = http.createServer((request, response) => {

    //request知识点
    //获取请求地址
    const url = request.url
    console.log(url)

    //response知识点
    //第一个参数是状态码,可以不为200,欺骗浏览器
    response.writeHead(200, {
        //应用程序/普通文本,打开页面后就会自动下载
        // 'content-type': 'application/plain'
        //纯文本(普通文本)
        // 'content-type': 'text/plain'
        //html
        // 'content-type': 'text/html'
        //json
        'content-type': 'application/json;charset=utf-8'

    })
    //默认的标头是可以识别html标签的,即默认就是html
    response.write('{"x":100}}')
    //表示结束函数,说明已经写完数据
    response.end()
})

//服务器的监听窗口
server.listen(8080, () => {
    console.log('server at http://localhost:8080...')
})

  • 测试:使用postman或者Insomnia进行数据请求

3.Insomina工具的使用

1.发送表单

server.js

const http = require('http')
const logger = require('../utils/log')
const querystring = require('querystring')

const server = http.createServer((request, response) => {

    const url = request.url

    let data = ''
    //接受参数
    //chunk是返回的数据流
    request.on('data', (chunk) => {
        data += chunk
    })

    request.on('end', () => {
        response.writeHead(200, {
            'content-type': 'application/json;charset=utf-8'
        })

        // response.write(`{"url":${url}}`)
        response.write(JSON.stringify(querystring.parse(data)))
        response.end()

    })

})


server.listen(8080, () => {
    console.log('server at http://localhost:8080...')
})

2.Insomina发送请求

在这里插入图片描述

4.GET请求

server.js

const http = require('http')
const logger = require('../utils/log')
const querystring = require('querystring')
const https = require('https')

const server = http.createServer((request, response) => {

    // logger.debug(https.get('https://m.xiaomiyoupin.com/mtop/mf/resource/data/batchList'))
    // 第一个参数是请求地址,第二个是回调函数
    //通过get请求获取到对象然后向前端返回数据,某种意义上实现了跨域访问
    https.get('https://m.xiaomiyoupin.com/mtop/mf/resource/data/batchList', (result) => {
        let data = ''
        result.on('data', (chunk) => {
            data += chunk
        })

        result.on('end', () => {

            response.writeHead(200, {
                'content-type': 'application/json;charset=utf-8'
            })

            response.write(data)
            response.end()
        })
    })

})


server.listen(8080, () => {
    console.log('server at http://localhost:8080...')
})

5.POST请求

  • 服务器提交(攻击)

  • 为了演示服务器攻击,我们首先需要建造一个伪服务器(express服务器,需要事先全局安装好express:npm i -g express-generator + npm i -g express ,注意是安装两个第三方库,而不是一个!):

    • ①创建一个项目文件夹:train-express-env
    • ②在终端输入express -e,这个之后会有关讲解,目前只是为了演示
    • ③安装依赖:npm i
    • ④启动服务器:npm start
    • ⑤在浏览器中输入地址:http://localhost:3000 ,这是默认express服务器的端口号
  • 然后我们就可以愉快的测试(攻击)这个服务器了


  • 服务器准备工作(创建服务器的业务中间件)

    • 创建工具包和工具log.js,请移步2.querystring的知识点,并找到该工具js
    • 在routes下的index.js中添加中间件
    var express = require('express');
    var router = express.Router();
    const logger = require('../utils/log')
    
    /* GET home page. */
    router.get('/', function (req, res, next) {
      res.render('index', { title: 'Express' });
    });
    
    //测试要用到的中间件,模拟服务器的业务,就是被攻击时要做的事情
    //我们模拟该业务为创建日志文件,并且不断追加内容,实际上还是不能够体现业务量的大
    router.post('/data', (req, res, next) => {
      logger.debug(req.body)
      res.send('ok')
    })
    
    module.exports = router;
    
    • 重启服务器

    • 测试:

      在这里插入图片描述

  • 为了方便我们还可以在package.json里面修改start脚本:

    • "start": "nodemon ./bin/www"

  • POST请求

①server.js

const https = require('https')
const http = require('http')
const querystring = require('querystring')

//提交的数据
//首先要封装data,生成querystring
const postData = querystring.stringify({
    province: '上海',
    city: '上海',
    district: '宝山区',
    address: '同济支路199号智慧七立方3号楼2-4层',
    latitude: 43.0,
    longitude: 160.0,
    message: '求购一条小鱼',
    contact: '13666666',
    type: 'sell',
    time: 1571217561
})


//请求参数

const option = {
    //协议,注意要冒号
    protocol: 'http:',
    //地址
    hostname: 'localhost',
    //请求方式
    method: 'POST',
    //端口号
    port: 3000,
    //路径
    path: '/data',
    //请求头
    headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
        'Content-Length': Buffer.byteLength(postData)
    }


}
const server = http.createServer((req, res) => {
    const request = http.request(option, (result) => {

    })

    //发送请求
    request.write(postData)
    request.end()

    //返回值
    res.end()
})

server.listen(8080, () => {
    console.log('server at http://localhost:8080')
})

②运行

nodemon server.js

③发送请求

在这里插入图片描述

④观察服务器日志

在这里插入图片描述

4.跨域

1.jsonp

  • 全称jsonpadding

  • CDN网站:https://www.bootcdn.cn/ ,当你不想下载js文件而想调用官方源的时候就可以去这个网站上面找

  • server.js

    • 运行:nodemon server.js
const url = require('url')
const http = require('http')

const server = http.createServer((req, res) => {
    let urlstr = req.url
    //解析成为对象,添加true获取请求的参数
    let urlObj = url.parse(urlstr, true)

    console.log(urlObj)
    switch (urlObj.pathname) {
        case '/api/data':
            //调用回调函数,用引号包裹,所以称之为json padding
            res.write(`${urlObj.query.cb}('hello')`)
            break
        default:
            res.write('404 page not found')
    }
    res.end()
})

server.listen(8080, () => {
    console.log('server at http://localhost:8080')
})
  • index.html
    • 运行:npx http-server -p 9000
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        function getData(data) {
            console.log(data)
        }
    </script>
    <script src="http://localhost:8080/api/data?cb=getData"></script>
</body>

</html>

2.CORS

  • 中文:跨源资源共享

  • 重点:'Access-Control-Allow-Origin': '*'

  • server.js

    • 启动服务器:nodemon server.js
const url = require('url')
const http = require('http')

const server = http.createServer((req, res) => {
    let urlstr = req.url
    //解析成为对象,添加true获取请求的参数
    let urlObj = url.parse(urlstr, true)

    console.log(urlObj)
    switch (urlObj.pathname) {
        case '/api/data':
            res.writeHead(200, {
                'content-type': 'application/json',
                'Access-Control-Allow-Origin': '*'
            })
            res.write('{"ret":true,"data":"hello"}')
            break
        default:
            res.write('404 page not found')
    }
    res.end()
})

server.listen(8080, () => {
    console.log('server at http://localhost:8080')
})
  • index.html
    • 运行服务器:npx http-server -p 9000
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <script>
        //浏览器自带的ajax请求
        fetch('http://localhost:8080/api/data')
            .then(response => response.json())
            .then(result => {
                console.log(result)
            })
    </script>

</body>

</html>

3.middleware(http-proxy-middware)

  • 中间件,http代理中间件方式进行跨域访问

  • 在npmjs官网查找用法

  • 安装中间件:npm i http-proxy-middleware -S

  • server.js

const http = require('http')
const url = require('url')
//导入中间件
const { createProxyMiddleware } = require('http-proxy-middleware')

const server = http.createServer((req, res) => {
    urlStr = req.url
    if (/\/ajax/.test(urlStr)) {
        // console.log(urlStr)
        const proxy = createProxyMiddleware('/ajax', {
            //目标网站
            target: 'https://mapi.vip.com',
            //是否切换源
            changeOrigin: true,
            //重写路径
            pathRewrite: {
                '^/ajax': ''
            }

        })
        //开启代理
        proxy(req, res)
    } else if (/\/api/.test(urlStr)) {
        const proxy2 = createProxyMiddleware('/api', {
            //目标网站2
            target: 'https://m.lagou.com',
            //是否切换源
            changeOrigin: true,


        })
        //开启代理
        proxy2(req, res)

    }
    else {
        console.log('error')
    }


})

server.listen(8080, () => {
    console.log('server at http://localhost:8080')
})

在这里插入图片描述

5.爬虫

const http = require('http')
const https = require('https')
const cheerio = require('cheerio')

function filterData(data) {
    //2.通过cheerio转换为虚拟DOM方便操作
    const $ = cheerio.load(data)
    // console.log(data)
    //3.进行有关操作
    $('.section-item-box p').each((index, el) => {
        console.log(index)
        console.log($(el).text())
    })
}

const server = http.createServer((req, res) => {
    let data = ''
    //1.首先通过https请求获取到页面
    https.get('https://www.meizu.com', (result) => {
        result.on('data', (chunk) => {
            data += chunk
        })
        result.on('end', () => {
            filterData(data)
        })
    })


})

server.listen(8080, () => {
    console.log('server at http://localhost:8080')
})

6.event

  • node.js的事件,与jquery类似

app.js

const EventEmitter = require('events')

class MyEventEmitter extends EventEmitter { }

const event = new MyEventEmitter()

//事件名,事件所有的参数
event.on('play', (value) => {
    console.log(value)
})
//事件可以重名,都会触发
event.on('play', (value) => {
    console.log(value)
})
event.on('play2', (value) => {
    console.log(value)
})

//触发事件,返回值
event.emit('play', 'movie')
event.emit('play2', 'tv')
//再次触发
event.emit('play2', 'tv')

7.File System

app.js

const fs = require('fs')
const fsP = require('fs').promises

// 创建文件夹,它的回调函数是错误优先的(指的是第一个参数必定是err)
fs.mkdir('./logs', (err) => {
    //如果有错误就直接抛出
    if (err) throw err
    console.log('文件夹创建成功')
})

// 文件夹改名
fs.rename('./logs', './log', () => {
    console.log('文件夹修改名字成功')
})

// 删除文件夹
fs.rmdir('./log', () => {
    console.log('文件夹删除成功')
})

// 写内容到文件里
fs.writeFile(
    //要书写内容的文件
    './logs/log1.txt',
    //要书写的内容
    'hello',
    // 错误优先的回调函数
    (err) => {
        if (err) {
            console.log(err.message)
        } else {
            console.log('文件创建成功')
        }
    }
)

// 给文件追加内容
fs.appendFile('./logs/log1.txt', '\nworld', () => {
    console.log('done.')
})

// 读取文件内容
fs.readFile('./logs/log1.txt', 'utf-8', (err, data) => {
    console.log(data)
})

// 删除文件
fs.unlink('./logs/log1.txt', (err) => {
    console.log('done.')
})

// 批量写文件
for (var i = 0; i < 10; i++) {
    fs.writeFile(`./logs/log-${i}.txt`, `log-${i}`, (err) => {
        console.log('done.')
    })
}

// 读取文件/目录信息
fs.readdir('./', (err, data) => {
    data.forEach((value, index) => {
        fs.stat(`./${value}`, (err, stats) => {
            // console.log(value + ':' + stats.size)
            console.log(value + ' is ' + (stats.isDirectory() ? 'directory' : 'file'))
        })
    })
})

// 同步读取文件
try {
    const content = fs.readFileSync('./logs/log-1.txt', 'utf-8')
    console.log(content)
    console.log(0)
} catch (e) {
    console.log(e.message)
}

console.log(1)

// 异步读取文件:方法一
//读取到的content实际上是buffer流,所以要加转码utf-8,或者不加,使用toString方法
fs.readFile('./logs/log-0.txt', 'utf-8', (err, content) => {
    console.log(content)
    console.log(0)
})
console.log(1)

// 异步读取文件:方法二
fs.readFile('./logs/log-0.txt', 'utf-8').then(result => {
    console.log(result)
})

// 异步读取文件:方法三
function getFile() {
    return new Promise((resolve) => {
        fs.readFile('./logs/log-0.txt', 'utf-8', (err, data) => {
            resolve(data)
        })
    })
}

//小括号或者中括号作为开头前面一般要加分号
; (async () => {
    console.log(await getFile())
})()

// 异步读取文件:方法四
const fsp = fsP.readFile('./logs/log-1.txt', 'utf-8').then((result) => {
    console.log(result)
})

console.log(fsP)

// watch 监测文件变化,和删除,除了新建
fs.watch('./logs/log-0.txt', () => {
    console.log(0)
})

8.流与zlib

1.stream

  • 基本上所有的读写文件操作实际上都是流的操作,该段代码已失效(2022.8.19),请查看官网最新API
const fs = require('fs')

const readstream = fs.createReadStream('./note.txt')
const writestream = fs.createWriteStream('./note2.txt')

writestream.write(readstream)

2.zlib

  • 对文件进行压缩,这个很重要
const fs = require('fs')
const zlib = require('zlib')

//做gzip压缩
const gzip = zlib.createGzip()

const readstream = fs.createReadStream('./note.txt')
const writestream = fs.createWriteStream('./note2.gzip')
//const writestream = fs.createWriteStream('./note2.txt')

readstream
//pipe管道操作,以下两个操作要分别进行
  .pipe(gzip)
//相当于直接进行拷贝
  .pipe(writestream)

//writestream.write(readstream)

9.readline

const readline = require('readline');

const rl = readline.createInterface({

    //标准输入流
    input: process.stdin,
    //标准输出流
    output: process.stdout
});

rl.question('What do you think of Node.js? ', (answer) => {
    // TODO: Log the answer in a database
    console.log(`Thank you for your valuable feedback: ${answer}`);

    rl.close();
});

10.Crypto

const crypto = require('crypto')

const password = 'abc123'

const hash = crypto
    // 使用sha1加密方式
    // .createHash('sha1')
    //使用MD5加密方式
    .createHash('md5')
    //如果有中文就要加utf-8,没有就不用
    .update(password, 'utf-8')
    //使用十六进制
    .digest('hex')

//加密后的密码位数一样
console.log(hash)
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值