Skip to content

商务合作:vTikTok


公众号:



首先安装Node.js

MAC安装

方式一

下载:https://nodejs.org/en

方式二

brew install node

查看安装版本:npm -v

npm模块安装路径:/usr/local/node/0.10.24/lib/node_modules/

Ubuntu安装

shell
sudo apt-get install nodejs
sudo apt-get install npm
sudo apt-get install nodejs
sudo apt-get install npm

PHP和Node.js运行服务器的区别

PHP 来编写后端的代码时(Java也一样),需要 Apache 或者 Nginx 的 HTTP 服务器,并配上 mod_php5 模块和 php-cgi。 等于是说PHP什么都不是自己的,要依赖人家Apache然后搭配PHP应用。

不过对 Node.js 来说,概念完全不一样了。使用 Node.js 时,我们不仅仅 在实现一个应用,同时还实现了整个 HTTP 服务器。

require 指令:在 Node.js 中,使用 require 指令来加载和引入模块,引入的模块可以是内置模块,也可以是第三方模块或自定义模块。

创建服务器:服务器可以监听客户端的请求,类似于 Apache 、Nginx 等 HTTP 服务器。

接收请求与响应请求 服务器很容易创建,客户端可以使用浏览器或终端发送 HTTP 请求,服务器接收请求后返回响应数据。

创建Node.js应用

步骤一、使用 require 指令来加载和引入模块

const module = require('module-name');

其中,module-name 可以是一个文件路径(相对或绝对路径),也可以是一个模块名称,如果是一个模块名称,Node.js 会自动从 node_modules 目录中查找该模块。

require 指令会返回被加载的模块的导出对象,可以通过该对象来访问模块中定义的属性和方法,如果模块中有多个导出对象,则可以使用解构赋值的方式来获取它们。

我们使用 require 指令来载入 http 模块,并将实例化的 HTTP 赋值给变量 http,实例如下:

var http = require("http");

步骤二、创建服务器

接下来我们使用 http.createServer() 方法创建服务器,并使用 listen 方法绑定 8888 端口。 函数通过 request, response 参数来接收和响应数据。

实例如下,在你项目的根目录下创建一个叫 server.js 的文件,并写入以下代码:

js
var http = require('http');

http.createServer(function (request, response) {

    // 发送 HTTP 头部 
    // HTTP 状态值: 200 : OK
    // 内容类型: text/plain
    response.writeHead(200, {'Content-Type': 'text/plain'});

    // 发送响应数据 "Hello World"
    response.end('Hello World\n');
}).listen(8888);

// 终端打印如下信息
console.log('Server running at http://127.0.0.1:8888/');
var http = require('http');

http.createServer(function (request, response) {

    // 发送 HTTP 头部 
    // HTTP 状态值: 200 : OK
    // 内容类型: text/plain
    response.writeHead(200, {'Content-Type': 'text/plain'});

    // 发送响应数据 "Hello World"
    response.end('Hello World\n');
}).listen(8888);

// 终端打印如下信息
console.log('Server running at http://127.0.0.1:8888/');

NPM 使用介绍

  1. npm包默认存放的位置:/usr/local/node/0.10.24/lib/node_modules/
  2. 或者是当前项目下的node_modules目录下,类似于Python的venv环境。

NPM是随同NodeJS一起安装的包管理工具,能解决NodeJS代码部署上的很多问题,常见的使用场景有以下几种:

允许用户从NPM服务器下载别人编写的第三方包到本地使用。 允许用户从NPM服务器下载并安装别人编写的命令行程序到本地使用。 允许用户将自己编写的包或命令行程序上传到NPM服务器供别人使用。 由于新版的nodejs已经集成了npm,所以之前npm也一并安装好了。同样可以通过输入 "npm -v" 来测试是否成功安装。命令如下,出现版本提示表示安装成功:

shell
1. npm install <Module Name> 本地安装
2. npm install -g cnpm 全局安装
3. npm install -g cnpm --registry=https://registry.npmmirror.com 使用淘宝镜像安装
1. npm install <Module Name> 本地安装
2. npm install -g cnpm 全局安装
3. npm install -g cnpm --registry=https://registry.npmmirror.com 使用淘宝镜像安装

本地安装指类似于Python的venv环境,只在当前项目下安装 将安装包放在 ./node_modules 下(运行 npm 命令时所在的目录),如果没有 node_modules 目录,会在当前执行 npm 命令的目录下生成 node_modules 目录。

全局安装:将安装包放在 /usr/local 下或者你 node.js 软件的系统安装目录。

安装好之后,express 包就放在了工程目录下的 node_modules 目录中,因此在代码中只需要通过 require('express') 的方式就好,无需指定第三方包路径。

var express = require('express');
var express = require('express');

npm list -g 查看已经安装的包(全局)

npm list grunt 查看某个包的版本号

npm的指令实在和pip太像了,所以这里就不多说了。

对比:

shell
pip install xxx
npm install xxx
pip install xxx
npm install xxx

使用淘宝 NPM 镜像

由于国内直接使用 npm 的官方镜像是非常慢的,这里推荐使用淘宝 NPM 镜像。 淘宝 NPM 镜像是一个完整 npmjs.org 镜像

cnpm指令替换npm指令

npm install -g cnpm --registry=https://registry.npmmirror.com:这样就可以使用 cnpm 命令来安装模块了:
cnpm install [name]
npm install -g cnpm --registry=https://registry.npmmirror.com:这样就可以使用 cnpm 命令来安装模块了:
cnpm install [name]

查看node包的信息

Package.json 属性说明

json
name - 包名。
version - 包的版本号。
description - 包的描述。
homepage - 包的官网 url 。
author - 包的作者姓名。
contributors - 包的其他贡献者姓名。
dependencies - 依赖包列表。如果依赖包没有安装,npm 会自动将依赖包安装在 node_module 目录下。
repository - 包代码存放的地方的类型,可以是 git 或 svn,git 可在 Github 上。
main - main 字段指定了程序的主入口文件,require('moduleName') 就会加载这个文件。这个字段的默认值是模块根目录下面的 index.js。
keywords - 关键字
name - 包名。
version - 包的版本号。
description - 包的描述。
homepage - 包的官网 url 。
author - 包的作者姓名。
contributors - 包的其他贡献者姓名。
dependencies - 依赖包列表。如果依赖包没有安装,npm 会自动将依赖包安装在 node_module 目录下。
repository - 包代码存放的地方的类型,可以是 git 或 svn,git 可在 Github 上。
main - main 字段指定了程序的主入口文件,require('moduleName') 就会加载这个文件。这个字段的默认值是模块根目录下面的 index.js。
keywords - 关键字

卸载包

npm uninstall express

更新包

npm update express

创建于发布(类似于Maven)

npm init npm publish

后端node.js框架

  1. express(简直就是FASTAPI的翻版)
  2. egg(阿里出品)
  3. koa(现在这个用的多)

Node.js 事件循环

虽然Node.js 是单进程单线程应用程序,但是因为 V8 引擎提供的异步执行回调接口,通过这些接口可以处理大量的并发,所以性能非常高。

Node.js 几乎每一个 API 都是支持回调函数的。

Node.js 基本上所有的事件机制都是用设计模式中观察者模式实现。

Node.js 单线程类似进入一个while(true)的事件循环,直到没有事件观察者退出,每个异步事件都生成一个事件观察者,如果有事件发生就调用该回调函数.

尽管Python和Node.js都是单线程的,但它们可以通过使用多进程或集群来实现并行处理,以提高性能和吞吐量。

Node.js的调试

  1. 第一种非常简单,使用vscode的调试功能,打开调试终端,打断点,直接运行node xxx.js即可。
  2. node --inspect=8888 app.js 这种一般针对web服务,可以在浏览器中输入chrome://inspect/#devices,然后点击inspect即可。

Node.js模块系统

类似于Python的模块导入,众所周知,Python的文件就是一个模块,模块名就是文件名。

  1. Node.js 提供了 exports 和 require 两个对象,其中 exports 是模块公开的接口,require 用于从外部获取一个模块的接口,即所获取模块的 exports 对象。
  2. 模块是 Node.js 应用程序的基本组成部分,文件和模块是一一对应的。换言之,一个 Node.js 文件就是一个模块,这个文件可能是 JavaScript 代码、JSON 或者编译过的 C/C++ 扩展。

定义模块

我们可以创建一个模块,并通过 module.exports 或 exports 对象把模块的内容导出,如下实例。

创建模块 math.js 代码如下:

js
exports.area = function (r) {
    return Math.PI * r * r;
};

exports.circumference = function (r) {
    return 2 * Math.PI * r;
};
exports.area = function (r) {
    return Math.PI * r * r;
};

exports.circumference = function (r) {
    return 2 * Math.PI * r;
};

引入模块

我们可以使用 require 指令来载入 Node.js 模块。

require() 方法用于加载模块,传入一个模块名,返回一个模块对象。

js
var math = require('./math.js');
var math = require('./math.js');

Node.js 路由

路由是由一个 URI(或者叫路径)和一个特定的 HTTP 方法(GET、POST 等)组成的,涉及到应用如何响应客户端对某个网站节点的访问。

路由是指如何定义应用的端点(URIs)以及如何响应客户端的请求。

路由是由一个 URI、HTTP 请求(GET、POST等)和若干个句柄组成,它的结构如下: app.METHOD(path, [callback...], callback), app 是 express 对象的一个实例, METHOD 是一个 HTTP 请求方法, path 是服务器上的路径, callback 是当路由匹配时要执行的函数。

路由的定义和使用

以下实例演示了在应用程序中如何定义路由以及如何让它与 HTTP 请求相匹配:

js
var express = require('express');
var app = express();

//  主页输出 "Hello World"

app.get('/', function (req, res) {
   console.log("主页 GET 请求");
   res.send('Hello GET');
})

//  POST 请求

app.post('/', function (req, res) {
   console.log("主页 POST 请求");
   res.send('Hello POST');
})

//  /del_user 页面响应

app.get('/del_user', function (req, res) {
   console.log("/del_user 响应 DELETE 请求");
   res.send('删除页面');
})

//  /list_user 页面 GET 请求

app.get('/list_user', function (req, res) {
   console.log("/list_user GET 请求");
   res.send('用户列表页面');
})

// 对页面 abcd, abxcd, ab123cd, 等响应 GET 请求

app.get('/ab*cd', function(req, res) {   
   console.log("/ab*cd GET 请求");
   res.send('正则匹配');
})

var server = app.listen(8081, function () {

  var host = server.address().address
  var port = server.address().port

  console.log("应用实例,访问地址为 http://%s:%s", host, port)

})
var express = require('express');
var app = express();

//  主页输出 "Hello World"

app.get('/', function (req, res) {
   console.log("主页 GET 请求");
   res.send('Hello GET');
})

//  POST 请求

app.post('/', function (req, res) {
   console.log("主页 POST 请求");
   res.send('Hello POST');
})

//  /del_user 页面响应

app.get('/del_user', function (req, res) {
   console.log("/del_user 响应 DELETE 请求");
   res.send('删除页面');
})

//  /list_user 页面 GET 请求

app.get('/list_user', function (req, res) {
   console.log("/list_user GET 请求");
   res.send('用户列表页面');
})

// 对页面 abcd, abxcd, ab123cd, 等响应 GET 请求

app.get('/ab*cd', function(req, res) {   
   console.log("/ab*cd GET 请求");
   res.send('正则匹配');
})

var server = app.listen(8081, function () {

  var host = server.address().address
  var port = server.address().port

  console.log("应用实例,访问地址为 http://%s:%s", host, port)

})

Node.js GET/POST请求

获取GET请求内容

由于GET请求直接被嵌入在路径中,URL是完整的请求路径,包括了?后面的部分,因此你可以手动解析后面的内容作为GET请求的参数。

node.js 中 url 模块中的 parse 函数提供了这个功能。

js
var http = require('http');
var url = require('url');
var util = require('util');

http.createServer(function(req, res){
    res.writeHead(200, {'Content-Type': 'text/plain; charset=utf-8'});

    // 解析 url 参数
    var params = url.parse(req.url, true).query;
    res.write("网站名:" + params.name);
    res.write("\n");
    res.write("网站 URL:" + params.url);
    res.end();
}).listen(3000);
var http = require('http');
var url = require('url');
var util = require('util');

http.createServer(function(req, res){
    res.writeHead(200, {'Content-Type': 'text/plain; charset=utf-8'});

    // 解析 url 参数
    var params = url.parse(req.url, true).query;
    res.write("网站名:" + params.name);
    res.write("\n");
    res.write("网站 URL:" + params.url);
    res.end();
}).listen(3000);

获取 POST 请求内容

POST 请求的内容全部的都在请求体中,http.ServerRequest 并没有一个属性内容为请求体,原因是等待请求体传输可能是一件耗时的工作。

比如上传文件,而很多时候我们可能并不需要理会请求体的内容, 恶意的POST请求会大大消耗服务器的资源,所以 node.js 默认是不会解析请求体的, 当你需要的时候,需要手动来做。

js
var http = require('http');
var querystring = require('querystring');
var util = require('util');

http.createServer(function(req, res){
    // 定义了一个post变量,用于暂存请求体的信息
    var post = '';     
 
    // 通过req的data事件监听函数,每当接受到请求体的数据,就累加到post变量中
    req.on('data', function(chunk){    
        post += chunk;
    });
 
    // 在end事件触发后,通过querystring.parse将post解析为真正的POST请求格式,然后向客户端返回。
    req.on('end', function(){    
        post = querystring.parse(post);
        res.end(util.inspect(post));
    });
}).listen(3000);
var http = require('http');
var querystring = require('querystring');
var util = require('util');

http.createServer(function(req, res){
    // 定义了一个post变量,用于暂存请求体的信息
    var post = '';     
 
    // 通过req的data事件监听函数,每当接受到请求体的数据,就累加到post变量中
    req.on('data', function(chunk){    
        post += chunk;
    });
 
    // 在end事件触发后,通过querystring.parse将post解析为真正的POST请求格式,然后向客户端返回。
    req.on('end', function(){    
        post = querystring.parse(post);
        res.end(util.inspect(post));
    });
}).listen(3000);

Node.js 处理GET/POST请求

在介绍 Node.js 处理 GET/POST 请求之前,我们先看看什么是 HTTP 协议,以及它的请求响应过程。

HTTP 协议

HTTP 是一个客户端和服务器端请求和响应的标准(TCP),用于从 WWW(万维网)服务器传输超文本到本地浏览器的传送协议。

HTTP 是一个在计算机世界里专门在两点之间传输文字、图片、音频、视频等超文本数据的约定和规范,由于它是在 TCP 协议之上运行的,所以传输的数据是可靠的,不会丢失。

HTTP 协议工作于客户端-服务端架构为上。浏览器作为 HTTP 客户端通过 URL 向 HTTP 服务端即 WEB 服务器发送所有请求。

Web 服务器有:Apache 服务器,IIS 服务器(Internet 信息服务)等。

Web 浏览器有:IE 浏览器,Firefox 浏览器,Google Chrome 浏览器,Opera 浏览器,Safari 浏览器等。

Node.js的全局对象

JavaScript 中有一个特殊的对象,称为全局对象(Global Object),它及其所有属性都可以在程序的任何地方访问,即全局变量。

在浏览器 JavaScript 中,通常 window 是全局对象, 而 Node.js 中的全局对象是 global,所有全局变量(除了 global 本身以外)都是 global 对象的属性。

在 Node.js 我们可以直接访问到 global 的属性,而不需要在应用中包含它。

全局对象与全局变量 global 最根本的作用是作为全局变量的宿主。按照 ECMAScript 的定义,满足以下条 件的变量是全局变量:

在最外层定义的变量; 全局对象的属性; 隐式定义的变量(未定义直接赋值的变量)。

当你定义一个全局变量时,这个变量同时也会成为全局对象的属性,反之亦然。需要注 意的是,在 Node.js 中你不可能在最外层定义变量,因为所有用户代码都是属于当前模块的, 而模块本身不是最外层上下文。

注意: 最好不要使用 var 定义变量以避免引入全局变量,因为全局变量会污染命名空间,提高代码的耦合风险。

  1. __filename:表示当前正在执行的脚本的文件名。它将输出文件所在位置的绝对路径,且和命令行参数所指定的文件名不一定相同。如果在模块中,返回的值是模块文件的路径。
  2. __dirname:表示当前执行脚本所在的目录。
  3. setTimeout(cb, ms):在指定的毫秒(ms)数后执行指定函数(cb)。:setTimeout() 只执行一次指定函数。
  4. clearTimeout(t):用于停止一个之前通过 setTimeout() 创建的定时器。参数 t 是通过 setTimeout() 函数创建的定时器。
  5. setInterval(cb, ms):在指定的毫秒(ms)数后执行指定函数(cb)。
  6. process:用于描述当前Node.js 进程状态的对象,提供了一个与操作系统的简单接口。通常在你写本地命令行程序的时候,少不了要和它打交道。

__filename 非常有用的一个全局属性,返回当前模块文件解析后的绝对路径,该属性其实并非全局而是模块作用域下的,它的值等于 __dirname + require.main.filename。

Node(TypeScript)和Python实在太相似了,可以完全按照Python来学习。

MVVM的经典就是VUE。