node.js 静态服务搭建 和 模块化系统——0821

node.js安装配置:
下载地址:https://nodejs.org/en/download/
安装教程:https://www.runoob.com/nodejs/nodejs-install-setup.html

在vsCode上下载包工具:Node Debug 和 node-snippets

一、创建简单的服务器

步骤:
1、引入http 协议模块 require('http')
2、创建服务器 createServer()
3、监听服务器端口 listen()
4、服务器运行 node ***.js

const http = require('http');
let port = 8000;
let hostname = "localhost"
const server = http.createServer((req, res) => {
    //res.writeHead(200, { "content-Type": "text/html;charset=utf8" });
    //设置请求头也可以分开写
    //设置状态码
    res.statusCode = 200;
    res.setHeader("content-Type", "text/html;charset=utf8");

    res.write("首页", (err) => {
        if (err)
            throw err;
    });
    res.end();
});
server.listen(port, () => {
    console.log(`服务器运行在:http://${hostname}:${port}/`);
})

注释:
(1)http 模块的 createServer() 方法 的callback中有两个参数,分别为 reqres。分别代表 request 请求头 ; response 响应头。

(2)上例中的res.end():向服务器发出信号,表明已发送所有响应头和主体,该服务器应该视为此消息已完成。 必须在每个响应上调用此 response.end() 方法。

res.end() 参数为dataencodingcallback

如果指定了 data,则相当于调用 response.write(data, encoding) 之后再调用 response.end(callback)

如果指定了 callback,则当响应流完成时将调用它。

(2)req 有一个属性是 req.url,用于返回请求的地址。

注意:
在node.js中文件修改需要重启服务:先 Ctrl+C 结束当前进程,再 node ***.js 重新运行服务器。

这样开发比较慢,可以安装自启动工具 supervisor

cnpm install --save-dev supervisor

安装完成之后启动文件使用supervisor ***.js
启动服务之后修改代码会自动启动服务

二、http模块的 get() 和 request() 方法

由于大多数请求都是不带请求体的 GET 请求,因此 Node.js 提供了这两个便捷的方法。

1、http.get(url,(res)=>{})
url 参数是请求的路径,res 里边是响应信息。
这个方法与 http.request() 唯一的区别是,它将请求方法设置为 GET 并且会自动调用 req.end()

//http模块的get方法
let http = require('http');
http.get("http://nodejs.cn/search", (res) => {
    console.log(res.statusCode);
});

2、http.request(url,(res)=>{})
url 参数是请求的路径,res里边是响应信息。
使用 http.request() 时,必须始终调用 req.end() 来表示请求的结束,即使没有数据被写入请求主体。

三、url 路径解析模块

url 路径解析模块 是 node.js 的内置模块,使用时可以直接引入 :

const url=require('url');

引入后就可以使用了:

使用时要注意: req 有一个自带的默认路径 "/favicon.ico",使用时需要处理。否则 req.url 就会输出两个路径,一个是该默认路径,一个是实际请求路径。

	//处理"/favicon.ico"
    if (req.url != "/favicon.ico") {
       //代码
    }

路径解析模块里边的方法
url.parse(req.url, true) :路径解析,true 表示将参数解析成 json 格式,默认是false。

解析后输出:
图1
上边输出结果中:
queryget 请求传的值(post传值使用req.body);
pathname 是路径名;
path 是路径。

四、commonjs ——模块化系统

Commonjs是模块化的标准,node.js 就是commonjs 模块化的实现。

在nodejs中,http,url,fs都是 nodejs 的内置模块,可以直接引入后使用。

Commonjs中自定义模块的实现:
在nodejs中将公共的功能抽离为单独的 js 文件作为模块,在外部是没有办法访问的(类似后端的私有属性和方法);
要想使用模块,就必须在模块里边通过exports或者module.exports暴露属性或者方法。在需要的模块使用require引入模块。(类似于自己定义依赖,就是自己做一个文件,把它放到node_modules依赖包文件里边)

使用require引入自定义模块时:
(1)可以直接使用文件相对目录引入,也可以使用以下方法:

(2)Nodejs 可以自动找 node_modules 文件下的文件,如果 node_modules 文件夹下有文件夹,可以cd进入这个文件,使用cnpm init –yes 安装当前文件的 package.json 配置文件,就可以直接require(‘filename’) 请求了;
具体步骤:

新建 node_modules 文件夹;
将自定义模块放到一个同名文件夹中,再将该文件夹放到 node_modules 里边;
cd 进入自定义模块所在文件夹;
使用cnpm init –yes 安装当前文件的 package.json 配置文件;
就可以直接require(‘filename’) 请求了。

五、 第三方模块安装和 package.json 项目文件

1、package.json 项目文件

创建node项目之后,先给整个项目安装 package.json 项目文件:在项目目录下 cnpm init --yes
安装后就类似于 vue 里边的 package.json。

--yes 强制按照严格模式命名。

2、第三方模块的安装和使用

安装之后直接 require 即可。

比如,引入md5-node模块:
安装:

cnpm install --save-dev md5-node

引入:

let md5=require(“md5-node”)

引入之后就可以使用了。

md5('1234')

六、FS 文件系统模块

FS——文件系统模块,是一组文件操作api,用来进行文件的读取和写入。

Fs模块中的方法均有同步(阻塞式)和异步(非阻塞式)版本。建议使用异步,性能更高,速度更快,没有阻塞。

异步方法函数最后一个参数为回调函数,回调函数的第一个参数包含了错误信息error)。

使用:因为是内置模块,所以直接 require 请求即可。

常用api:

(1)fs.readFile 异步读取文件

参数:path
flags (一般写r+,可读可写),
mode(设置文件模式(权限),默认为0666可读可写),
callback(err,str) 第一个参数err是错误信息,第二个参数str是读取到的数据(buffer类型,打出到页面要toString)。

     fs.readFile("./duction/stu.txt", { flag: "r+", mode: 0666 }, (err, str) => {
         if (err)
             throw err;
         //读取到的是buffer值
         console.log(str);
         res.write(str.toString());
         res.end()
     })

(2)Fs.readFileSync同步读取文件

参数是path

let str=fs.readFileSync("./duction/stu.txt")
res.write(str.toString());

(3)Fs.open 异步打开文件

参数:pathcallback(err,fd)
fd 是文件描述符 。

            fs.open("./duction/stu.txt", (err, fd) => {
                if (err) {
                    console.log("文件打开失败");
                    throw err;
                }
                else console.log("文件打开", fd);
            })

(4)fs.stat 异步检测文件信息

参数:pathcallback(err,stats)

stats的方法:
stats.isFile() 检测是否是文件;
stats.isDirectory() 检测是否是文件夹。

            fs.stat("./duction/stu.txt", (err, stat) => {
                if (err)
                    throw err;
                else {
                    console.log(stat.isFile());
                    console.log(stat.isDirectory());
                }
            })

面试题:
有一个文件夹,包含子文件和子文件夹,检测哪个是文件,哪个是文件夹?

            let baseurl = "./";
            let basename = "duction";
            let check = (base, name) => {
                let src = base + name;
                fs.stat(src, (err, stats) => {
                    if (err)
                        throw err;
                    else {
                        if (stats.isDirectory()) {
                            //目录
                            console.log(name, "---directory");
                            //如果是目录  打开目录
                            fs.open(src, (error, fd) => {
                                if (error)
                                    throw error;
                                else {
                                    //读取目录
                                    fs.readdir(src, (e, files) => {
                                        if (e)
                                            throw e;
                                        else {
                                            //对读取到的每个文件进行检测
                                            for (let val of files) {
                                                let url = src + "/";
                                                check(url, val);
                                            }
                                        }
                                    })
                                }
                            })
                        }
                        else {
                            //是文件
                            console.log(name, "---file");
                        }
                    }

                })
            }
            check(baseurl, basename);

(5)fs.writeFile 异步写入文件

写入时没有该文件,则自动创建

一次性写入,会覆盖原先的文本。

参数:file(文件名或文件描述符),
data(要写入文件的数据,可以是String字符串或Buffer缓冲对象),
options(对象),
callback(err)

fs.writeFile("./duction/data.txt", "这是写入的内容", { flag: "w", mode: 0666 }, (err) => {
    if (err) {
        console.log("写入失败");
        throw err;
    }
    else {
        console.log("写入成功");
    }
})

(6)fs.read 异步读取文件(可以分段读取)

读取前要先打开文件。

参数:fd(通过fs.open()方法返回的文件描述符),
buffer(数据写入的缓冲区),
offset(缓冲区写入的写入偏移量),
length(要从文件中读取的字节数),
position(文件读取的起始位置,如果position的值为null,从当前文件的指针位置读取),
callback(err,bytesRead,buffer)

let buffer = Buffer.alloc(500);
fs.open("./duction/stu.txt", (err, fd) => {
    if (err)
        throw err;
    else {
        console.log("文件打开,开始读取!");
        fs.read(fd, buffer, 0, buffer.length, null, (error, bytes) => {
            if (error)
                throw error;
            else {
                //读取完成后关闭文件  操作读取到的buffer
                fs.close(fd, (e) => {
                    if (e)
                        throw e;
                    else {
                        console.log(buffer.toString(),bytes);
                    }
                })
            }
        })
    }
})

注意:
使用分段读取时,可能会把读取到的最后一个字截成两半,造成乱码。如下图:
图2
解决方案:
将每次读取到的buffer存到一个完整的buffer里边,最后一次性转成字符串(buffer本身是一个存储二进制字节的数组)

代码如下:

let buff = Buffer.alloc(0);
let buffer = Buffer.alloc(500);
fs.open("./duction/stu.txt", "r+", (err, fd) => {
    if (err)
        throw err;
    else {
        let count = 0;
        console.log("文件打开,开始读取!");
        let readfile = () => {
            //每次读取的位置  buffer.length*count
            fs.read(fd, buffer, 0, buffer.length, buffer.length * count, (error, bytes) => {
                if (error)
                    throw error;
                else {
                    if (bytes > 0) {
                        buff = Buffer.concat([buff, buffer.slice(0, bytes)]);
                        count++;
                        readfile();
                    }
                    else {
                        //读取完成后关闭文件  操作读取到的buffer
                        fs.close(fd, (e) => {
                            if (e)
                                throw e;
                            else {
                                console.log("文件关闭成功!");
                                console.log(buff.toString());
                            }
                        })
                    }
                }
            })
        };
        readfile();
    }
})

(7)fs.close 异步关闭文件

参数:fdcallback(err)

(8)fs.ftruncate 异步截取文件

功能: 截取一定字节内的文件内容,超出部分将被去除。

使用前得先打开文件

参数:fdlen(文件内容截取的长度),callback(err)

let buffer = Buffer.alloc(2048);
fs.open("./duction/stu.txt", "r+", (err, fd) => {
    if (err)
        throw err;
    else {
        console.log("文件打开成功!");
        //开始截取
        fs.ftruncate(fd, 300, (error) => {
            if (error) {
                throw error;
                console.log("文件截取失败!");
            }
            else {
                console.log("文件截取成功!");
                //读取文件
                fs.read(fd, buffer, 0, buffer.length, null, (e, bytes) => {
                    if (e)
                        throw e;
                    console.log(buffer.toString());
                })
            }
        })
    }
})

上边代码截取了300个字符的内容,再读取这个文件时,就只能读取到300个字符的内容。

(9)fs.unlink 删除文件

(创建文件: fs.writeFile会自动创建)

参数:pathcallback(err)

(10)fs.mkdir 创建目录

参数:path
options包含recursive -是否以递归的方式创建目录,默认为false;mode-设置目录权限,默认为0777 ;
callback(err)

案例:
登录QQ,创建对应的目录,如果存在,删除目录;如果不存在,创建目录并在该目录下写入文件。

let query = url.parse(req.url, true).query;
let qq = query.qq;
let url = "./" + qq;
fs.mkdir(url, (err) => {
    if (err) {
        console.log("该目录已经存在!");
        //如果目录已存在  删除目录
        fs.rmdir(url, (error) => {
            if (error) {
                //目录里边有内容时  会删除失败
                console.log("目录删除失败!");
                //删除目录里边的文件
                fs.unlink(url + "/data.txt", (errinfo) => {
                    if (errinfo) {
                        console.log("文件删除失败!");
                    }
                    else {
                        console.log("文件删除成功!");
                    }
                })
            }
            else {
                console.log("删除成功!");
            }
        })
    }
    else {
        console.log("目录创建成功!准备写入文件!");
        //在该目录下写入文件
        fs.writeFile(url + "/data.txt", "写入的数据", (e) => {
            if (e) {
                console.log("写入文件失败!");
            }
            else {
                console.log("写入文件成功!");
            }
        })
    }
})

(11)fs.readdir 读取目录

参数:pathcallback(err,files) files 是目录中文件的名称的数组

(12)fs.rmdir 删除目录

该目录里边有文件时不能直接删除

参数:pathcallback(err)

(13)fs.rename 重命名

参数:oldpathnewpathcallback(err)

fs.rename("./duction", "./direction", (err) => {
    if (err) {
        console.log("重命名失败");
    }
    else {
        console.log("重命名成功");
    }
})

(14)fs.appendFile 文件追加式写入

异步的追加数据到文件,如果文件尚不存在,就创建文件。

参数:pathdataoptionscallback(err)

fs.appendFile("./direction/data.txt", "\n这是追加的内容", (err) => {
    if (err) {
        console.log("追加失败!");
    }
    else {
        console.log("追加成功!");
    }
})
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值