moonshot 6 - Node.js 1

148 阅读7分钟

铺垫

  • 两个问题
  1. 为什么浏览器可以运行JavaScript? 因为浏览器中有JS解析引擎,各个浏览器使用的解析引擎不一样,其中Chrome浏览器使用的V8引擎性能最好。

  2. 为什么JavaScript可以操作DOM和BOM? 因为每个浏览器都内置了DOM、BOM甚至AJAX相关的API函数。因此JS可以调用它们。

  • 运行环境 运行环境是指代码正常运行所必需的必要环境。

例如Chrome浏览器运行环境,包括V8引擎内置API(例如DOM、BOM、Canvas、XMLHttpRequest、JS内置对象等等)。

简介

  • 什么是Node.js Node.js是一个基于Chrome V8引擎的JavaScript运行环境

  • Node.js运行环境 Node.js运行环境包括V8引擎内置API(例如fs、path、http、JS内置对象、querystring等等)。

注意浏览器是JavaScript的前端运行环境,Node.js是JavaScript的后端运行环境。在Node.js运行环境中无法调用DOM、BOM、AJAX等浏览器内置的API。

  • Node.js的使用
  1. 编写好一段JS代码
  2. win+R输入cmd打开终端
  3. cd命令进入到代码所在目录下
  4. 输入node 文件名运行该JS代码 也可以在代码所在目录下直接按住shift键再点鼠标右键打开Powershell窗口。

Powershell和cmd都是windows系统下的终端,只不过Poweshell是cmd的升级版,更新、功能也更多。

fs 模块

  1. fs.readFile() 该方法用于读取文件,并有三个参数
    参数1:要读取文件的存放路径
    参数2:读取文件时采取的编码格式,一般默认指定utf8(可选)
    参数3:读取操作结束后的回调函数,参数是读取失败和读取成功的结果
// 导入 fs 模块
const fs = require('fs')

fs.readFile('./test.txt', 'utf8', function (err, dataStr) {
    // 若读取失败则err是一个错误对象,dataStr是undifined
    // 若读取成功则err是null,dataStr是读取的那个文件里的内容
    console.log(err);
    console.log(dataStr);
})
  1. fs.writeFile() 该方法用于向文件中写入内容,并有四个参数
    参数1:要写入内容的文件的存放路径
    参数2:要写入的内容,该参数只能传入字符串,并且会覆盖之前文件中已有的内容
    参数3:写入文件时采取的编码格式,一般默认指定utf8(可选)
    参数4:写入操作结束后的回调函数,参数是写入失败的结果
// 导入 fs 模块
const fs = require('fs')

fs.writeFile('./test.txt', ' hello fs!', 'utf-8', function (err) {
    // 若写入失败则err是一个错误对象
    // 若写入成功则err是null
    if (err === null) {
        console.log('文件写入成功!');
    }
    else {
        console.log('文件写入失败!');
        console.log(err);
    }
})

补充三个函数方法:

  1. let newArr = someStr.split('规定字符') // 把字符串用规定的字符分割成数组
  2. let newStr = someArr.join('规定字符') // 把数组中的每个元素用规定的字符拼接成字符串
  3. someStr.replace('旧字符', '新字符') // 自动搜索字符串里的旧字符,并替换成新字符
  1. 路径问题 不管我们用fs.readFile()还是fs.writeFile(),都要使用到文件的路径,我们在传入一个路径作为参数的时候可以用相对路径和绝对路径,但是相对路径可能会发生一些错误,使用绝对路径又损失了移植性。

所以我们通常会使用一个对象__dirname来表示文件执行的当前目录。

fs.readFile(__dirname + '/test.txt', 'utf-8', function (err, dataStr) {
    if (err) {
        console.log('读取错误!');
        console.log(err);
    }
    else {
        console.log(dataStr);
    }
})

path 模块

  1. path.join() 该方法用于拼接路径
// 导入 path 模块
const path = require('path')

const pathStr = path.join(__dirname, '/test.txt')

console.log(pathStr) // C:\Users\Citizen7\Desktop\moonshot\MS6_Node_1\test.txt
  1. path.basename() 该方法用于返回一个文件路径的最后一个路径,即文件名
// 导入 path 模块
const path = require('path')

const fpath = 'C:/Users/Citizen7/Desktop/moonshot/MS6_Node_1/test.txt'

console.log(path.basename(fpath)) // test.txt
console.log(path.basename(fpath, '.txt')) // test
  1. path.extname() 该方法用于返回一个文件路径的拓展名
// 导入 path 模块
const path = require('path')

const fpath = 'C:/Users/Citizen7/Desktop/moonshot/MS6_Node_1/test.txt'

console.log(path.extname(fpath)) // .txt

案例 1

将一个包含有CSS、JS和HTML代码的HTML页面分割成CSS、JS、HTML三个部分,并分别放入三个文件中。

// 导入模块
const fs = require('fs');
const path = require('path');

// 定义正则表达式
const regStyle = /<style>[\s\S]*<\/style>/;
const regScript = /<script>[\s\S]*<\/script>/;

// 读取文件
fs.readFile(path.join(__dirname, '/aim.html'), 'utf-8', function (err, dataStr) {
    if (err) {
        return console.log('读取出错!' + err.message);
    }
    else {
        resolveCSS(dataStr);
        resolveJS(dataStr);
        resolveHTML(dataStr);
    }
});

// 处理CSS的方法
function resolveCSS(htmlStr) {
    // 使用正则提取需要的内容
    let cssArr = regStyle.exec(htmlStr);
    // 将提取出来的字符串,进行字符串的replace替换操作 
    let newCSS = cssArr[0].replace('<style>', '').replace('</style>', '');
    // 将处理完的CSS字符串写入到新的文件中
    fs.writeFile(path.join(__dirname, '/aim/index.css'), newCSS, 'utf-8', function (err) {
        if (err) {
            return console.log('写入CSS出错!' + err.message);
        }
        else {
            console.log('写入CSS成功!');
        }
    })
}

// 处理JS的方法
function resolveJS(htmlStr) {
    // 使用正则表达式提取<script>标签里的内容,放入数组里
    let jsArr = regScript.exec(htmlStr);
    // 将提取出来的字符串(即数组的第一个元素)进行replace替换操作
    let newJS = jsArr[0].replace('<script>', '').replace('</script>', '');
    // 将处理完成的字符串写入新的文件中
    fs.writeFile(path.join(__dirname, '/aim/index.js'), newJS, 'utf-8', function (err) {
        if (err) {
            return console.log('写入JS出错!' + err.message);
        }
        else {
            console.log('写入JS成功!');
        }
    })
}

// 处理HTML方法
function resolveHTML(htmlStr) {
    // 把原始的html页面中的css和js部分替换掉
    let newHTML = htmlStr
        .replace(regStyle, '<link rel="stylesheet" href="./index.css" />')
        .replace(regScript, '<script src="./index.js"></script>');
    // 写入新的文件中
    fs.writeFile(path.join(__dirname, '/aim/index.html'), newHTML, 'utf-8', function (err) {
        if (err) {
            console.log('写入HTML出错!' + err.message);
        }
        else {
            console.log('写入HTML成功!');
        }
    })
}

http 模块

  • 服务器
  1. IP地址 互联网中的每一台计算机都有一个唯一的IP地址,每台计算机之间的通信都必须通过IP地址来访问,IP地址是形如127.112.41.1的数字。在我们开发过程中127.0.0.1就是我们本机的IP地址。

  2. 域名 IP地址固然可以唯一标识每一台计算机,但是毕竟不好记忆,所以我们可以为每一个IP地址起一个域名,形如www.juejin.cn,它对应的IP地址就是220.185.186.124(可以在终端中用ping 域名命令来查看域名的IP地址)。即使我们有了域名,也不能直接通过域名来访问一台服务器,它只是方便人们使用,在互联网中必须经过 域名服务器(DNS)来将域名与IP地址一一对应起来,再通过IP地址去访问服务器。

  3. 端口 一台作为服务器的计算机有一个IP地址(域名),但这个服务器内部可以有多种服务,客户端想要指定访问这台服务器的某一种服务,就需要在IP地址或者域名后面指定一个端口号,每一个端口号对应一个不同的服务。

  • 创建简单的web服务器
// 导入 http 模块
const http = require('http');

// 创建 web 服务器实例
const server = http.createServer();

// 为服务器实例绑定事件,监听客户端的请求
server.on('request', (req, res) => {
    console.log('Someone visit our web server.');
    
    // req 是客户端的请求对象,里面包含了与客户端相关的数据和属性
    console.log(req.url); // url 属性存放了请求的 url
    console.log(req.method); // method 属性存放了请求的方式
    
    // res 是服务器的响应对象,里面包含了与服务器相关的数据和属性
    let str = `Your request url is ${req.url}, and request method is ${req.method}`;
    res.end(str); // res.end() 函数会将指定的内容响应到页面上,并结束此次响应
});

// 启动服务器
server.listen(80, () => {
    console.log('Server running at http://127.0.0.1:80.');
});

image.png

需要注意,当res.end()向客户端发送的内容中有中文字符时,实际显示的时候会出现乱码,这时候需要设置一个响应头res.setHeader('Content-Type', 'text/html; charset=utf-8')

  • 动态响应内容 根据不同的请求URL,响应不同的内容
const http = require('http');
const server = http.createServer();

// 当服务器被请求时执行以下函数
server.on('request', (req, res) => {
    let url = req.url;

    // 默认的响应内容
    let content = '<h1>404 Not Found</h1>';

    // 判断请求的地址是否为首页或关于页面
    if (url === '/' || url === '/index.html') {
        content = '<h1>首页</h1>';
    }
    else if (url === '/about.html') {
        content = '<h1>关于页面</h1>';
    }

    // 设置响应头,防止中文乱码
    res.setHeader('Content-Type', 'text/html; charset=utf-8');

    // 发送响应内容到页面
    res.end(content);
});

// 当代码执行到这里时会启动服务器
server.listen(8080, () => {
    console.log('Server running at http://127.0.0.1:8080.');
});

案例 2

综合了上述三个模块的使用

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

// 创建 web 服务器
const server = http.createServer()

// 监听服务器的请求事件
server.on('request', (req, res) => {
    // 获取客户端请求的url地址
    const url = req.url
    
    // 把请求的url地址映射为本地文件的存放路径
    let fpath = ''
    if (url === '/') {
        // 如果客户端请求的是根目录,则默认是index.html
        fpath = path.join(__dirname, '/aim/index.html')
    }
    else {
        // 如果客户端请求的不是根目录,也提前写上 /aim 目录
        fpath = path.join(__dirname, '/aim', url)
    }

    // 设置响应头
    res.setHeader('Content-Type', 'text/html; charset=utf-8')

    // 读取本地文件并响应到页面
    fs.readFile(fpath, 'utf-8', (err, dataStr) => {
        if (err) {
            return res.end('<h1>404 Not Found.</h1>')
        }
        else {
            res.end(dataStr)
        }
    })
})

// 启动服务器
server.listen(8081, () => {
    console.log('Server running at http://127.0.0.1:8081.')
})