30、Node.js 开发实用指南与对象属性配置解析

Node.js 开发实用指南与对象属性配置解析

1. Node.js 文件系统操作

在 Node.js 里,文件系统操作存在同步和异步两种版本。同步版本借助异常处理错误,为让示例更健壮,可将其包裹于 try/catch 块中。例如:

try {
    fs.writeFileSync(path.join(__dirname, 'hello.txt'), 'hello from Node!');
} catch(err) {
    console.error('Error writing file.');
}

同步文件系统函数使用起来较为简便,但在编写 Web 服务器或网络应用时,要牢记 Node 的性能源于异步执行,此时应始终使用异步版本。若编写命令行工具,使用同步版本通常没问题。

可运用 fs.readdir 列出目录中的文件,示例代码如下:

const fs = require('fs');
fs.readdir(__dirname, function(err, files) {
    if(err) return console.error('Unable to read directory contents');
    console.log(`Contents of ${__dirname}:`);
    console.log(files.map(f => '\t' + f).join('\n'));
});

fs 模块还包含诸多文件系统函数,如下表所示:
| 功能 | 函数 |
| ---- | ---- |
| 删除文件 | fs.unlink |
| 移动或重命名文件 | fs.rename |
| 获取文件和目录信息 | fs.stat |

2. Process 对象的使用

每个运行的 Node 程序都能访问 process 变量,借此获取自身执行信息并加以控制。

2.1 退出程序

若应用遭遇严重错误,不适宜或无意义继续执行(即致命错误),可调用 process.exit 立即停止执行,还能提供数字退出码,脚本会依据此码判断程序是否成功退出。惯例上,退出码 0 表示“无错误”,非零退出码表示有错误。示例如下:

const fs = require('fs');
fs.readdir('data', function(err, files) {
    if(err) {
        console.error("Fatal error: couldn't read data directory.");
        process.exit(1);
    }
    const txtFiles = files.filter(f => /\.txt$/i.test(f));
    if(txtFiles.length === 0) {
        console.log("No .txt files to process.");
        process.exit(0);
    }
    // process .txt files...
});

2.2 命令行参数

process.argv 数组包含传递给程序的命令行参数。例如,编写一个统计文件行数的程序:

const fs = require('fs');
const filenames = process.argv.slice(2);
let counts = filenames.map(f => {
    try {
        const data = fs.readFileSync(f, { encoding: 'utf8' });
        return `${f}: ${data.split('\n').length}`;
    } catch(err) {
        return `${f}: couldn't read file`;
    }
});
console.log(counts.join('\n'));

2.3 环境变量

通过 process.env 对象可访问环境变量,环境变量常用于配置程序的某些行为。例如,使用 DEBUG 环境变量控制程序是否输出调试信息:

const debug = process.env.DEBUG === "1" ?
    console.log :
    function() {};
debug("Visible only if environment variable DEBUG is set!");

2.4 当前工作目录

process.cwd 能告知当前工作目录, process.chdir 可更改当前工作目录。示例如下:

console.log(`Current directory: ${process.cwd()}`);
process.chdir(__dirname);
console.log(`New current directory: ${process.cwd()}`);

3. 操作系统信息获取

os 模块可提供运行应用的计算机的特定平台信息,示例代码如下:

const os = require('os');
console.log("Hostname: " + os.hostname());          // prometheus
console.log("OS type: " + os.type());               // Linux
console.log("OS platform: " + os.platform());       // linux
console.log("OS release: " + os.release());         // 3.13.0-52-generic
console.log("OS uptime: " +
    (os.uptime()/60/60/24).toFixed(1) + " days");   // 80.3 days
console.log("CPU architecture: " + os.arch());      // x64
console.log("Number of CPUs: " + os.cpus().length); // 1
console.log("Total memory: " +
    (os.totalmem()/1e6).toFixed(1) + " MB");        // 1042.3 MB
console.log("Free memory: " +
    (os.freemem()/1e6).toFixed(1) + " MB");         // 195.8 MB

4. 子进程管理

child_process 模块可让应用运行其他程序,该模块暴露了三个主要函数: exec execFile fork ,同时也有对应的同步版本。

4.1 函数特点

  • exec :调用 shell 执行命令,若能在命令行运行的命令,就能用 exec 运行。
  • execFile :直接执行可执行文件,内存和资源使用稍优,但通常需更谨慎使用。
  • fork :用于执行其他 Node 脚本,会调用单独的 Node 引擎,不过能提供一些进程间通信选项。

4.2 示例代码

使用 exec 执行 dir 命令:

const exec = require('child_process').exec;
exec('dir', function(err, stdout, stderr) {
    if(err) return console.error('Error executing "dir"');
    stdout = stdout.toString(); // convert Buffer to string
    console.log(stdout);
    stderr = stderr.toString();
    if(stderr !== '') {
        console.error('error:');
        console.error(stderr);
    }
});

5. 流的使用

在 Node 中,流是处理数据的重要概念。流可分为读取流、写入流和双工流。

5.1 写入流

创建并使用写入流的示例:

const ws = fs.createWriteStream('stream.txt', { encoding: 'utf8' });
ws.write('line 1\n');
ws.write('line 2\n');
ws.end();

5.2 读取流

创建并使用读取流的示例:

const rs = fs.createReadStream('stream.txt', { encoding: 'utf8' });
rs.on('data', function(data) {
    console.log('>> data: ' + data.replace('\n', '\\n'));
});
rs.on('end', function(data) {
    console.log('>> end');
});

5.3 流的管道操作

使用管道操作将一个文件的内容复制到另一个文件:

const rs = fs.createReadStream('stream.txt');
const ws = fs.createWriteStream('stream_copy.txt');
rs.pipe(ws);

6. Web 服务器搭建

Node 最初的用途是提供 Web 服务器,借助 http 模块的 createServer 方法可轻松创建基本 Web 服务器。示例代码如下:

const http = require('http');
const server = http.createServer(function(req, res) {
    console.log(`${req.method} ${req.url}`);
    res.end('Hello world!');
});
const port = 8080;
server.listen(port, function() {
    console.log(`server startd on port ${port}`);
});

大多数操作系统出于安全考虑,不允许无提升权限监听默认 HTTP 端口(80),开发和测试时通常监听 1024 以上的端口。

当访问 http://localhost:8080 时,会看到 Hello world! ,同时控制台会记录请求信息,可能会看到两个请求:

GET /
GET /favicon.ico

这是因为大多数浏览器会隐式请求一个图标用于显示在 URL 栏或标签中。

6.1 处理特定请求

若有 favicon.ico 文件,可直接响应此请求:

const server = http.createServer(function(req, res) {
    if(req.method === 'GET' && req.url === '/favicon.ico') {
        const fs = require('fs');
        fs.createReadStream('favicon.ico');
        fs.pipe(res);       // this replaces the call to 'end'
    } else {
        console.log(`${req.method} ${req.url}`);
        res.end('Hello world!');
    }
});

7. 对象属性配置与代理

7.1 访问器属性

对象属性分为数据属性和访问器属性。访问器属性有 getter 和 setter 两个函数,访问时更像数据属性而非函数。

7.2 示例代码

传统方式定义 User 类:

const USER_EMAIL = Symbol();
class User {
    setEmail(value) {
        if(!/@/.test(value)) throw new Error(`invalid email: ${value}`);
        this[USER_EMAIL] = value;
    }
    getEmail() {
        return this[USER_EMAIL];
    }
}
const u = new User();
u.setEmail("john@doe.com");
console.log(`User email: ${u.getEmail()}`);

使用访问器属性重写 User 类:

const USER_EMAIL = Symbol();
class User {
   set email(value) {
      if(!/@/.test(value)) throw new Error(`invalid email: ${value}`);
      this[USER_EMAIL] = value;
   }
   get email() {
      return this[USER_EMAIL];
   }
}
const u = new User();
u.email = "john@doe.com";
console.log(`User email: ${u.email}`);

7.3 只读属性示例

定义一个计算矩形周长的只读属性:

class Rectangle {
    constructor(width, height) {
        this.width = width;
        this.height = height;
    }
    get perimeter() {
        return this.width*2 + this.height*2;
    }
}

综上所述,本文详细介绍了 Node.js 的文件系统操作、 process 对象、操作系统信息获取、子进程管理、流的使用、Web 服务器搭建以及对象属性配置等方面的知识,并给出了丰富的代码示例,希望能帮助读者更好地掌握 Node.js 开发。

8. 技术总结与流程梳理

8.1 关键技术总结

技术模块 核心功能 关键函数/方法
文件系统操作 同步和异步文件读写、目录读取等 fs.writeFileSync fs.readdir fs.unlink fs.rename fs.stat
Process 对象 程序退出控制、获取命令行参数和环境变量、管理当前工作目录 process.exit process.argv process.env process.cwd process.chdir
操作系统信息获取 获取计算机平台相关信息 os.hostname os.type os.platform os.release os.uptime os.arch os.cpus os.totalmem os.freemem
子进程管理 运行其他程序 exec execFile fork
流的使用 数据读写和传输 fs.createWriteStream fs.createReadStream rs.pipe
Web 服务器搭建 创建基本 Web 服务器并处理请求 http.createServer server.listen
对象属性配置 定义和使用访问器属性 get set

8.2 流程梳理 - Web 服务器请求处理流程

graph TD;
    A[客户端发起请求] --> B[服务器接收请求];
    B --> C{判断请求类型和 URL};
    C -- GET / --> D[记录请求信息并返回 'Hello world!'];
    C -- GET /favicon.ico --> E[读取 favicon.ico 文件并返回];
    D --> F[响应结束];
    E --> F;

9. 操作步骤详解

9.1 创建 Web 服务器详细步骤

  1. 引入 http 模块
const http = require('http');
  1. 创建服务器实例
const server = http.createServer(function(req, res) {
    // 处理请求逻辑
    console.log(`${req.method} ${req.url}`);
    if(req.method === 'GET' && req.url === '/favicon.ico') {
        const fs = require('fs');
        fs.createReadStream('favicon.ico').pipe(res);
    } else {
        res.end('Hello world!');
    }
});
  1. 指定服务器监听端口
const port = 8080;
server.listen(port, function() {
    console.log(`server startd on port ${port}`);
});

9.2 使用流复制文件详细步骤

  1. 创建读取流
const rs = fs.createReadStream('stream.txt');
  1. 创建写入流
const ws = fs.createWriteStream('stream_copy.txt');
  1. 使用管道操作复制文件
rs.pipe(ws);

10. 常见问题与解决方法

10.1 文件操作错误处理

在进行文件操作时,可能会遇到文件不存在、权限不足等错误。可使用 try/catch 块捕获同步操作的错误,异步操作则在回调函数中处理错误。

// 同步操作错误处理
try {
    fs.writeFileSync('nonexistent/path/hello.txt', 'hello from Node!');
} catch(err) {
    console.error('Error writing file:', err.message);
}

// 异步操作错误处理
fs.readdir('nonexistent/dir', function(err, files) {
    if(err) {
        console.error('Error reading directory:', err.message);
    } else {
        // 处理文件列表
    }
});

10.2 Web 服务器端口占用问题

若指定的端口已被其他程序占用,服务器将无法启动。可尝试更换端口,如将 port 改为其他未被使用的端口。

const port = 8081; // 更换端口
server.listen(port, function() {
    console.log(`server startd on port ${port}`);
});

11. 综合示例 - 带环境变量配置的文件行数统计程序

11.1 需求说明

编写一个程序,接收多个文件名作为命令行参数,统计每个文件的行数,并根据环境变量 DEBUG 控制是否输出调试信息。

11.2 代码实现

const fs = require('fs');
const filenames = process.argv.slice(2);
const debug = process.env.DEBUG === "1" ? console.log : function() {};

debug('Starting line count program...');

let counts = filenames.map(f => {
    try {
        const data = fs.readFileSync(f, { encoding: 'utf8' });
        return `${f}: ${data.split('\n').length}`;
    } catch(err) {
        return `${f}: couldn't read file`;
    }
});

console.log(counts.join('\n'));

debug('Line count program finished.');

11.3 运行步骤

  1. 正常运行(不输出调试信息)
node linecount.js file1.txt file2.txt
  1. 开启调试信息输出
# Unix 系统
export DEBUG=1
node linecount.js file1.txt file2.txt

# Windows 系统
set DEBUG=1
node linecount.js file1.txt file2.txt

12. 总结与展望

12.1 总结

本文全面介绍了 Node.js 开发中的多个重要方面,包括文件系统操作、 process 对象、操作系统信息获取、子进程管理、流的使用、Web 服务器搭建以及对象属性配置等知识。通过丰富的代码示例和详细的操作步骤,帮助读者深入理解和掌握这些技术的使用方法。

12.2 展望

Node.js 作为一个强大的 JavaScript 运行环境,在 Web 开发、服务器端编程等领域有着广泛的应用前景。未来,随着技术的不断发展,Node.js 可能会在性能优化、功能扩展等方面取得更大的突破。例如,可能会出现更高效的异步处理机制、更便捷的模块管理方式等。同时,Node.js 与其他技术的结合也将更加紧密,如与前端框架 React、Vue.js 等的集成,为开发者提供更完整的开发解决方案。

希望读者通过本文的学习,能够在实际项目中灵活运用这些技术,提高开发效率和代码质量。在后续的学习和实践中,不断探索和发现 Node.js 的更多可能性。

**项目名称:** 基于Vue.jsSpring Cloud架构的博客系统设计开发——微服务分布式应用实践 **项目概述:** 本项目为计算机科学技术专业本科毕业设计成果,旨在设计并实现一个采用前后端分离架构的现代化博客平台。系统前端基于Vue.js框架构建,提供响应式用户界面;后端采用Spring Cloud微服务架构,通过服务拆分、注册发现、配置中心及网关路由等技术,构建高可用、易扩展的分布式应用体系。项目重点探讨微服务模式下的系统设计、服务治理、数据一致性及部署运维等关键问题,体现了分布式系统在Web应用中的实践价值。 **技术架构:** 1. **前端技术栈:** Vue.js 2.x、Vue Router、Vuex、Element UI、Axios 2. **后端技术栈:** Spring Boot 2.x、Spring Cloud (Eureka/Nacos、Feign/OpenFeign、Ribbon、Hystrix、Zuul/Gateway、Config) 3. **数据存储:** MySQL 8.0(主数据存储)、Redis(缓存会话管理) 4. **服务通信:** RESTful API、消息队列(可选RabbitMQ/Kafka) 5. **部署运维:** Docker容器化、Jenkins持续集成、Nginx负载均衡 **核心功能模块:** - 用户管理:注册登录、权限控制、个人中心 - 文章管理:富文本编辑、分类标签、发布审核、评论互动 - 内容展示:首页推荐、分类检索、全文搜索、热门排行 - 系统管理:后台仪表盘、用户内容监控、日志审计 - 微服务治理:服务健康检测、动态配置更新、熔断降级策略 **设计特点:** 1. **架构解耦:** 前后端完全分离,通过API网关统一接入,支持独立开发部署。 2. **服务拆分:** 按业务域划分为用户服务、文章服务、评论服务、文件服务等独立微服务。 3. **高可用设计:** 采用服务注册发现机制,配合负载均衡熔断器,提升系统容错能力。 4. **可扩展性:** 模块化设计支持横向扩展,配置中心实现运行时动态调整。 **项目成果:** 完成了一个具备完整博客功能、具备微服务典型特征的分布式系统原型,通过容器化部署验证了多服务协同运行的可行性,为云原生应用开发提供了实践参考。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值