凡是可以用 JavaScript 来写的应用,终将都会用 JavaScript 来写。—— Atwood 定律

Node.js 简称"服务端 JavaScript ",是基于谷歌 v8 引擎的 js 运行环境,可以让 JavaScript 在服务器端执行。相比于后端人员,JavaScript 对于前端来说再熟悉不过了,入门还是相对简单的。这章包含的内容如下:

  • 安装 Node.js 及相关配置
  • 常用的应用模块
  • 简易 HTTP 服务器和自定义模块
  • 事件驱动
  • 常见的状态码

# 安装 Node.js 及相关配置

可从 Node.js 官网 (opens new window),下载对应平台的 Node 版本进行安装,一路完成即可。

完成后在命令行界面输入以下两个命令,检验是否安装成功:

# node -v //查看node版本
# npm -v  //查看npm版本

使用 npm 命令安装模块

npm install <Module Name>

你也可以使用 yarn 命令安装模块

yarn add <Module Name>

关于如何安装 Node.js,这里就不赘述了,如果打印报错,请自行百度谷歌。

# 常用的应用模块

Node.js 提供了各种丰富的 JavaScript 模块库(自带的+第三方),极大简化了使用 Node.js 来扩展Web应用程序的开发。

Node Package Manager,简称 npm,是一个基于 Node.js 的包管理器,也是整个 Node.js 社区最流行、支持的第三方模块最多的包管理器。通过 npm,方便直接下载引用第三方发布模块,提高开发效率。

常用内置模块有:

  • http
  • path
  • url
  • events
  • fs
  • crypto加密
  • os
  • process

# 简易HTTP服务器和自定义模块

Node.js 基于 CommonJS 规范,主要分为模块定义、模块引用和模块标识,但 Node.js 在实现中并非完全按照 CommonJS 规范实现,而是对模块规范进行了一定的取舍。简单记住就是:引入模块用 require,输出模块用 module.exports。

网上有很多教程都会教你把所有的逻辑都放进一个用 Node.js 写的基础 HTTP 服务器里。但是如果我想加入更多的内容,同时还想保持代码的可读性呢?

实际上,只要把不同功能的代码放入不同的模块中,保持代码分离还是相当简单的。

让我们先从服务器模块开始。在项目的根目录下创建一个叫 app.js 的文件,并写入以下代码(记得动手敲起来哦):

const http = require('http');
const url = require('url'); //引用内置模块url
http.createServer(function(req, res) {
	res.writeHead(200, {
   'Content-Type': 'text/plain'
	}); //设置头信息
	let pathname = url.parse(req.url).pathname; //把请求网址交给url 对象处理
	let bodyStr = ""; //定义一个变量,用来存储要输出的内容
	if (pathname === "/") { //如果是首页
		bodyStr = 'Hello Uniapp\n';
	} else {
		bodyStr = 'Happy Uniapp\n'; //如果是其他路径
	}
	res.end(bodyStr); //输出内容
}).listen(3000); //绑定端口
console.log('Server running at http://localhost:3000/'); //控制台输出提示

然后在终端输入脚本:

node app.js

接下来,打开浏览器访问 http://localhost:3000/,你会看到页面写着Hello Uniapp,如果是 http://localhost:3000/happy,会显示Happy Uniapp。

就这么简单,你已经启动了服务器。只要敲入键盘Ctrl+C就可以停止服务。

接下来创建一个自定义模块 testA.js 文件,并写下如下代码:

function helloUniapp(){
	console.log("Hello Uniapp");
}

module.exports = helloUniapp;

我们在testA模块里面声明了一个helloUniapp函数,并且通过 module.exports 对外暴露该函数,在需要地方通过引入该模块,就可以使用helloUniapp函数方法。

我们再写一个 app.js 文件,引入该模块并使用

const helloUniapp = require('./testA');	//引入testA模块

helloUniapp()  		// 执行showAge()函数  输出`Hello Uniapp`

在引用时注意引用的路径,上面两个文件是在同一目录下,所以用的相对路径。

在上面看到例如const http = require("http")的方式引用,这时 Node.js 会依次在内置模块、全局模块(即node_modules文件夹)下查找http模块,如果查找不到,就会报错!

# 事件驱动

Node.js 设计天生就是基于事件驱动。事件驱动可以理解为发布/订阅模式,当进来的一个新的请求的时候,请求将会被压入队列中,因为单线程关系,会通过一个循环来检测队列中的事件状态变化,如果检测到有状态变化的事件,那么就执行该事件对应的回调函数。

看个栗子直观理解:

// 引入 events 模块
const events = require('events');
// 创建 eventEmitter 对象
const eventEmitter = new events.EventEmitter();

// 绑定 helloAction 事件
eventEmitter.on('helloAction', function(d){
   console.log(d); // 'Hello Uniapp。'
});

// 触发 helloAction 事件
eventEmitter.emit('helloAction', 'Hello Uniapp。');

console.log("程序执行完毕。");
Hello Uniapp。
程序执行完毕。

# 常见的状态码

  • 200 OK 服务器成功处理了请求
  • 301/302 Moved Permanently(重定向)请求的URL已移走。Response中应该包含一个Location URL, 说明资源现在所处的位置
  • 304 Not Modified(未修改)客户端的缓存资源是最新的,使用客户端缓存
  • 400 Bad Request 传参有误
  • 403 Forbidden 禁止访问,一般是没有权限
  • 404 Not Found 未找到资源
  • 500 Internal Server Error服务器内部错误

# 小结

本章讲了 Node.js 的几个基础知识:安装与配置,常用模块,HTTP服务,自定义模块和状态码,下一章会基于 Koa.js 框架实现简单的 Restful Api。

关于 Node.js 相关知识远远不止这些,网上专门讲 node.js 的教程和书籍有很多,我推荐《深入浅出Node.js》,可以反复看,讲得非常细致。

阅读全文