JavaScript之Node.js(一):node功能与fs() path() http()内置模块

1、基础知识node.js

(1)JS解析引擎
让代码可以被执行。不同的浏览器使用不同的解析引擎。
chrome ------V8,性能好。
firefox ------odinMonkey
srfri----jscore
IE------chakra
(2)
API常用的
DOM/BOM/ajax,等待执行的JS代码,调用WEB API,给JS解析引擎。
运行环境,代码正常运行所需要的必要环境。chrome浏览器运行环境,V8解析引擎,内置API函数。
V8引擎负责解析执行代码,内置API是运行环境的特殊接口,浏览器提供的,只能在所属的运行环境中调用。
JS是否可以做后端开发?后端开发一般用JAVA/PYTHON/PHP。JS也可以做后端开发,但是要借助node.js实现。node.js是后端的一个运行环境。
(3)什么是node.js
白龙网看来,是一个基于V8引擎的JS运行环境。如果JS代码放在浏览器,则是做前端开发,如果把JS代码放到node.js运行环境,则是做后端开发。
node.js的运行环境,包括V8引擎和内容API(fs/path/http/JS内置对象/querystring等),API提交给V8解析引擎。
浏览器是JS的前端运行环境;Node.js是JS的后端运行环境;node.js中无法调用DOM/BOM/AJAX等等浏览器内容API。
(4)Node.js能做什么?
提供了基础功能与API,
express框架----->构建WEB应用
electron框架----->构建跨平台的桌面应用
restfy框架------>构建API接口
读写操作数据库,创建实用的命令行工具辅助前端开发……
JS学习路径:
基础语法->浏览器内置API->第三方库(jq/atr-template);
node.js学习路径:
JS基础语法-》node.js内置API-》第三方模块。
(5)node.js安装
LTS版本:长期稳定版本,推荐安装;
current版本:新特性尝鲜,热衷于新特性的用户可以使用。
打开命令窗口/终端(Terminal),输入node -v 查看node.js版本号,说明安装成功。
(6)在node.js环境是执行JS代码
win+R,打开cmd终端,使用命令cd切换到js文件所在的路径,然后输入node js文件名,即可执行JS命令。
或者在js文件所在目录,按住shift+右键,打开powershell窗口,直接输入node js名称,即可执行JS代码。
(7)终端快捷键
方向键上,快速定位上一个命令;
tab键,快速补全输入命令;
esc,快速清空当前输入的命令;
cls,清空当前终端内容;

2、fs文件系统模块

文件系统模块,操作谁的的模块,提供了方法和属性,满足用户对文件 的操作需要。如果要在JS中使用FS操作文件,则需要先使用命令require('fs')导入它。
(1)fs.readFile() 读取文件指定的内容
①语法格式与使用步骤
A.新建一个测试文本文件1.txt并输入任意内容
B.新建一个JS文件1.js并输入如下代码
  //1.导入fs
  const fs = require('fs')
  //2.读取文件
  // 2-1第一参数是个字符串,指明被操作文件的路径
  // 2-2第二个参数是编码格式,一般为utf8
  // 2-3第三个参数是回调函数,带两个形参:读取失败、读取成功
  fs.readFile('./11.txt','utf8',function(err,dataStr) {
      console.log(err);
      console.log('-----------');
      console.log(dataStr);
  // 3.读取结果
  // 3-1如果读取成功,err的值为null,dataStr正常输出
  // 3-2如果读取失败,err值为错误对象,dataStr的值为undefined
  } )
C.打开powershell终端运行node 1.js
②利用回调函数形参返回结果判断文件是否读取成功
  const fs = require('fs')
  fs.readFile('./1.txt','utf8',function(err,dataStr) {
      //1.如果err=true,高读取文件失败并给出提示
      if(err) {
          return console.log('文件读取失败' + err.message);
      }
      //2.如果err=null,则读取文件成功并打印
      console.log('文件读取成功' + dataStr);
  } )
 
(2)fs.writeFile() 向指定的文件中写入内容
 
语法格式
    //1.导入文件系统
    const fs = require('fs')
    //2.调用fs.write()
    // 2-1第一个参数是字符串,声明写入的文件路径;如果本地有2.txt,则直接写入,如果没有写入的文件,则自动创建该文件后再写入
    // 2-2第二个参数是要写入的数据
    // 2-3第三个参数,是数据的编码格式,默认utf8,可以写,也可以省略
    // 2-4第四个参数,是回调函数,带一个形参
    fs.writeFile('./2.txt','白龙网','utf8',function(err) {
    // 3.写入成功,则err的值为null,写入失败,则err的值为错误对象
        console.log(err);
    })
 
判断写入是否成功
    const { log } = require('console');
    const fs = require('fs')
    fs.writeFile('./2.txt','白龙网','utf8',function(err) {
        console.log(err);
        if(err) {
            return console.log('写入失败' + err.message);
        }
        console.log('文件写入成功');
    })
案例1:考试成绩管理
    //1.导入文件系统
    const { log } = require('console')
    const fs = require('fs')
    //2.调用读取方法
    fs.readFile('./成绩.txt','utf8',function(err,dataStr) {
        //3.判断读取数据是否成功
        if(err) {
            return console.log('读取文件失败:' + err.message);
        }
        console.log('文件读取成功' + dataStr);
        // 4-1把字符串分割成数组1,用空格隔开
        const arrOld = dataStr.split(' ')
        console.log(arrOld);
        // 4-2遍历数组,并替换等号,把修改后的内容放入新数组2
        const arrNew = [];
        arrOld.forEach(item => {
            const str = item.replace('=',':');
            arrNew.push(str);
        })
        console.log(arrNew);
        // 4-3把数组2拼接成字符串
        const newStr = arrNew.join('\r\n');
        console.log(newStr);
        //5.fs.readFile()把处理好的数据写入新文件
        fs.writeFile('./ok.txt',newStr,function(err){
            if(err) {
                return console.log('成绩写入失败' + err.message);
            }
            console.log('成绩写入成功\n' + newStr);
        })
    })
 
路径动态拼接问题
   在使用fs模块操作文件时,如果提供的操作以./  ../开发的相对路径时,很容易出现路径动态拼接错误的问题。
   原因是,代码在运行的时候,会以执行node命令时所处的目录,动态的拼接出被操作文件的完整路径。
   如果要解决这个问题,可以在读写文件时,提供绝对路径即可。这个问题解决了路径拼接的问题,但是可移植性差,并且在JS中一个\表示转义,两个\\才表示\,如下:
   C:\\Users\\bailong\\Desktop\\node\\ok.txt
   终极解决办法是,使用__dirname(当前目录)再拼接相对路径,即可实现动态路径正确拼接的问题:
      const fs = require('fs')
      //1.使用__dirname动态拼接路径
      fs.readFile(__dirname + '/成绩.txt','utf8',function(err,dataStr) {
          if(err) {
              return console.log('读取文件失败:' + err.message);
          }
          console.log('文件读取成功' + dataStr);
          const arrOld = dataStr.split(' ')
          console.log(arrOld);
          const arrNew = [];
          arrOld.forEach(item => {
              const str = item.replace('=',':');
              arrNew.push(str);
          })
          console.log(arrNew);
          const newStr = arrNew.join('\r\n');
          console.log(newStr);
      //2.使用__dirname动态拼接路径
          fs.writeFile(__dirname + '/ok.txt',newStr,function(err){
              if(err) {
                  return console.log('成绩写入失败' + err.message);
              }
              console.log('成绩写入成功\n' + newStr);
          })
      })
     

3、path路径模块

处理路径的模块,满足用户对路径的处理需求。在使用下述方法之前,要先导入路径模块:const path = require('path')
(1)path.join()把多个路径片段拼接成一个完整的路径字符串
    凡是涉及路径拼接,都可以使用paht.join()方法来实现。
    const { log } = require('console');
    const path = require('path');
    const fs = require('fs');
    //../会抵消一级目录
    const pathStr = path.join('/a','/b/c','../','/d','/e');
    console.log(pathStr);
    //用path.join()拼接fs.readFile()方法第一个路径参数
    fs.readFile(path.join(__dirname,'./ok.txt'),'utf-8',function(err,dataStr) {
        if(err) {
            return console.log('读取失败' + err.message);
        }
        console.log(dataStr);
    })
 
(2)paht.basename()从路径字符串中,把文件名解析出来
这个方法可以获取路径的最后一部分,通过用这个方法获取路径中的文件名。
    const path = require('path');
    const fpath = 'a/b/c/d/index.html';
    //获取完整的文件名
    const fullName = path.basename(fpath);
    console.log(fullName);
    //返回index,第二参数是文件的扩展名,如果存在,会删除文件的扩展名,只返回文件名
    const fullName2 = path.basename(fpath,'.html');
    console.log(fullName2);
    //获取文件的扩展名
    const fext = path.extname(fullName);
    console.log(fext);
案例1:时钟案例
把一个含有HTML、JS、CSS方文档拆分为三个文件:index.html、index.js、index.css
//导入文件模块
const fs = require('fs')
//导入路径模块
const path = require('path')
//定义正则表达式,匹配所有CSS/JS
const regStyle = /<style>[\s\S]*<\/style>/;
const regJs = /<script>[\s\S]*<\/script>/;
//读取文件内容
fs.readFile(path.join(__dirname,'./index.html'),'utf-8',function(err,dataStr) {
    if(err) {
        return console.log('读取html失败' + err.message);
    }
    // console.log(dataStr);a
    //调用3个函数,分别提取html/css/js
    resolveCss(dataStr);
    resolveJs(dataStr);
    resolveHtml(dataStr);
})
//CSS处理函数
function resolveCss(htmlCss) {
    //使用正则表达式选取样式
    const r1 = regStyle.exec(htmlCss)
    //替换样式的开始、结束标识
   const newCss = r1[0].replace('<style>','').replace('</style>','')
    //把样式写稿css.css文件
fs.writeFile(path.join(__dirname,'/clock/css.css'),newCss,'utf-8',function(err) {
    if(err) {
        return console.log('写入CSS失败' + err.message);
    }
    console.log('样式成功定稿css.css文件');
})
}
//JS处理函数
function resolveJs(htmlStr) {
    const r2 = regJs.exec(htmlStr);
    // console.log(r2);
    const newJs = r2[0].replace('<script>','').replace('</script>','')
    fs.writeFile(path.join(__dirname,'./clock/js.js'),newJs,'utf-8',function(err) {
        if(err) {
            return console.log('JS写入失败' + err.message);
        }
        console.log('JS数据写入成功');
    })
}
//html处理函数
function resolveHtml(htmlStr) {
    //把内联样式、JS转换为外联样式、JS
    const newHtml = htmlStr.replace(regStyle,'<link rel="stylesheet" href="./css.css">').replace(regJs,'<script src="./js.js"></script>');
    fs.writeFile(path.join(__dirname,'./clock/index.html'),newHtml,'utf-8',function(err) {
        if(err) {
            return console.log('写入HTML失败' + err.message);
        }
        console.log('HTML成功写入');
    })
}
注意:
fs.writeFile()只能用来创建文件,不能创建目录;
重复调用fs.writeFile(),新内容会覆盖旧内容,不会报错;
 

4、http模块

(1)http模块概念与作用
消费资源的电脑叫客户端;提供资源的电脑叫服务器。
创建WEB服务器模块,通过HTTP模块提供的http.createServer()方法,就能把一台变成一台WEB服务器,对外提供WEB服务。同时,在使用http模块之前,要先导入:const http = reuqire('http)
服务器与普通电脑的区别,在于是否安装了服务器软件,如IIS/APACHE/ PHPSTUDY等。
node.js不需要使用第三方服务器软件,可以通过http模块,通过几行简单的代码就能的手写一个服务器软件,从而对外提供WEB服务器软件。
(2)服务器相关概念
IP地址,每台服务器都有自己的IP地址。
域名,IP地址的别名,
IP与域名是一一对应的关系,IP与域名对应关系的服务器是域名服务器DNS。
127.0.0.1  localhost
端口号,如同门牌号,每个WEB服务对应一个端口号。URL中的80端口可以被省略,只有80端口可以省略。apache默认端口号是80。
(3)创建基本的web服务器
①方法:
导入http模块;const http = require('http)
创建web服务器实例;const server = http.createServer()
为服务器实例绑定request事件,监听客户端请求;server.on('request',function(req,res) {})
启动服务器:server.listen(80,()=>{})
在vscode“终端->新建终端”新建一个终端用来运行JS。
    const http = require('http');
    const server = http.createServer();
    server.on('request',function(req,res) {
        console.log('welcome visit web server');
    });
    server.listen(8080,function() {
        console.log(('server running at 127.0.0.1'));
    })
②req请求对象
只要服务器接收了客户端的请求,就会调用通过server.on()为服务器绑定的request事件处理函数。如果想在事件处理函数中,访问与客户端相关的数据或者属性,可以使用req.url,req.method等。
    const http = require('http');
    const server = http.createServer();
    server.on('request',(req) => {
        const url = req.url;
        const method = req.method;
        const str = 'url=' + url + '\n' + 'method=' + method;
        console.log(str);
    })
    server.listen(80,() => {
        console.log('server running at http://localhost');
    })
③res响应对象
res.end()用来响应内容,结束请求过程。
const http = require('http');
const server = http.createServer();
server.on('request',(req,res) => {
    const url = req.url;
    const method = req.method;
    const str = 'url=' + url + '\n' + 'method=' + method;
    // 响应用户请求的数据
    res.end(str)
})
server.listen(80,() => {
    console.log('server running at http://localhost');
})
④解决中文乱码
const http = require('http');
const server = http.createServer();
server.on('request',(req,res) => {
    const url = req.url;
    const method = req.method;
    const str = '你请求的网址是:' + url + '\n' + '你请求的类型是:' + method;
    //如果出现乱码,可以指定编辑格式为utf-8
    res.setHeader('content-type','text/html;charset=utf-8');
    // 响应用户请求的数据
    res.end(str)
})
server.listen(80,() => {
    console.log('server running at http://localhost');
})
⑤根据不同url响应不同的页面
const http = require('http');
const server = http.createServer();
server.on('request',(req,res) => {
    //1.获取URL
    const url = req.url;
    //2.定义一个变量
    let content = '404 Not found';
    //3.判断首页内容显示
    if(url === '/' || url === '/index.html') {
        content = '<h1>首页</h1>';
    //4.判断列表页内容显示
    } else if (url === '/about.html') {
        content = '<h1>关于我们</h1>'
    }
    //5.防止乱码
    res.setHeader('content-type','text/html;charset=utf-8');
    //6.响应给用户的数据
    res.end(content);
});
server.listen(8088,() => {
    console.log('server is running at http://127.0.0.1');
})
⑥时钟web服务器的搭建
这个服务器的搭建重点是获取到相对路径后,把它拼接成完整的绝对路径;然后根据网站首页,列表页,分别从后台拼接出对应的页面路径。
    //1、导入模块
    const http = require('http');
    const fs = require('fs');
    const path = require('path');
    //2、创建服务器
    const server = http.createServer()
    //3、监听服务器事件
    server.on('request',(req,res) => {
        //3-1获取文件的url
        const url = req.url;
        console.log('123');
        //3-2把请求的url映射为具体的文件存放路径,判断如果是首页,就从后端拼接一个/clock的目录,如果是其它目录,就增加一级目录
        // const fpath = path.join(__dirname,url);
        let fpath = '';
        if(url === '/') {
            fpath = path.join(__dirname,'./clock/index.html');
        }else {
            fpath = path.join(__dirname,'./clock',url);
        }
        //读取文件并响应给客户端
        fs.readFile(fpath,'utf-8',(err,dataStr) => {
            if(err) {
                return res.end('404 Not found');
            }
            res.end(dataStr);
        })
    })
    //4、启动服务器
    server.listen(80,() => {
        console.log('server running at http://127.0.0.1');
    })