Nodejs学习笔记,1 Nodejs安装+借助express模块简单部署服务器


 先简介一下nodejs和NPM。Nodejs是2009年末Ryan Dahl在柏林的JavaScript大会上宣布的一项新技术,这项技术是关于在服务器端运行JavaScript的(是对JavaScript在浏览器端运行的方式的一种颠覆)。Nodejs是一个基于Chrome V8引擎的JavaScript运行环境,而NPM则是用Nodejs开发的JavaScript包管理工具(作为Nodejs的一个扩展模块)。

 有了Nodejs,无需再将书写好的代码部署到独立安装的Web服务器中去运行(Nodejs此时轻蔑地看了一眼NetBeans)。

1.1 下载和安装

  • https://nodejs.org下载Windows版的msi安装包。有两种版本的(LTS和Current),LTS可以满足大多数用户需求的,Current版本则包含了更多的新特征;
  • 安装过程相当简单,打开安装包一路next就行了,唯一需要注意的是要记住安装的目录,之后设置模块全局目录需要用到(如果以后使用时发现安装中遗漏了哪些功能也可以再次打开安装包进行修复,nodejs的设计理念是之一就是只维护少量的依赖,因此其编译和安装变得非常简单);
  • 安装之后打开cmd输入node -vnpm -v验证安装结果,如果安装成功都会出现相应的版本号(现在安装nodejs就顺带安装了npm这个模块了);
  • 安装结束后,在系统的环境变量PATH中自动被添加了Nodejs的安装路径,亲测后发现,如果这个路径丢了或被改了,在终端输入node或npm,cmd就会像看傻子一样告诉你这俩东西”“不是内部或外部命令,也不是可运行的程序或批处理文件”。

1.2 什么是REPL?如何使用?

 REPL(Read Eval Print Loop),交互式解译器,表示一个电脑的环境,类似于Windows终端(cmd)或者Unix/Linux shell,Nodejs 的交互式解释器可以很好的调试 Javascript 代码;

只要在终端中输入node并回车即可启动;

交互式解释器,可以执行以下任务:

  • 读取 - 读取用户输入,解析输入了Javascript 数据结构并存储在内存中。
  • 执行 - 执行输入的数据结构
  • 打印 - 输出结果
  • 循环 - 循环操作以上步骤直到用户两次按下 ctrl-c 按钮退出。

下面是两个常用的REPL命令:

  • Ctrl + C + CCtrl + D - 退出REPL(以前不知道每次都要重启cmd)
  • .help - 列出使用命令

1.3 npm对单一模块的安装和删除功能

参考自:https://blog.csdn.net/yihanzhi/article/details/75665959

针对安装单个模块的情况,包含安装、删除、保存为package.json三个内容。

  1. npm安装模块
    • $ npm install xxx利用 npm 安装xxx模块到当前命令行所在目录
    • $ npm install -g xxx利用npm安装全局模块xxx;
  2. 本地安装时将模块写入package.json中
    • $ npm install xxx安装但不写入package.json;
    • $ npm install xxx –save安装并写入package.json的”dependencies”中;
    • $ npm install xxx –save-dev安装并写入package.json的”devDependencies”中;
  3. npm 删除模块
    • $ npm uninstall xxx删除xxx模块;
    • $ npm uninstall -g xxx删除全局模块xxx;

1.4 通过package.json自定义模块(安装模块)

 自我感觉,nodejs开发就是模块的开发,创建一个文件夹作为模块,然后用package.json定义该模块的名称(name)、版本(version)、依赖(dependencies)、开发者依赖(devDependencies)等字段,我们在该模块内进行开发、测试等功能,也可以把这个模块发布出去。

 package.json是一个用于自定义模块的文件,(严格采用json格式)来定义自建的模块,其主要针对单个文件夹,使用npm安装时,会根据dependencies字段中的依赖项来重置该文件夹下的node_modules子文件夹,若不存在node_modules则会新建(也就是说,如果原来node_modules中有东西,也会被清空并替换成dependencies中的模块)。package.json的简单格式如下所示:(其中,只有name字段和version字段是必不可少的,dependencies字段中列出了自建模块需要的依赖项,依赖模块后面是版本号)

{
    "name": "my-colors-project",
    "version": "0.0.1",
    "dependencies": {
        "colors": "0.5.0"
    }
}

安装模块的流程如下:

  1. 新建文件夹,并定位到该文件夹

    $ mkdir my-project

    $ cd my-project

  2. 在文件夹下新建package.json文件,按照json格式输入nameversion两个字段(在dependencies字段中定义要使用的依赖模块及其版本号
  3. 使用npm安装(先定位到当前文件夹下)

    $ npm install

  4. 若需要添加模块到package.json文件中,可以在定位到文件夹目录后,使用下面两条命令来执行(package.json文件一定要存在):

    $ npm install xxx –save安装并写入package.json的“dependencies”中;

    $ npm install xxx –save-dev安装并写入package.json的“devDependencies”中;

注意事项:

  • 若所在文件夹下没有package.json文件,使用$ npm install xxx -save功能后,会产生致命后果:nodejs安装目录下的node_modules文件夹被重置,安装xxx模块相依赖的模块;
  • 定位到global目录后,使用$ npm install xxx -save命令时,即便global目录下包含package.json文件,也不会记录dependencies字段

1.5 设置全局目录

 全局目录包含两部分:cache(缓存)和global(模块包),默认安放在C盘的User\Administrator下,可以通过命令$ npm config get cache$ npm config get prefix查看当前cache目录和global目录。

 为了方便管理,我们在nodejs的安装目录下新建两个文件夹:node_cachenode_global,然后在终端使用$ npm config set cache ""$ npm config set global ""命令设置全局目录(”“中为node_cachenode_global的绝对路径名)。

 设置完成后,安装和删除单个模块时在后方加上-g就可以对该目录下的模块操作了。

2 部署网站

2.1 安装express模块

2.2 使用js文件部署服务器

首先创建一个js文件,在里面输入代码段:

var express = require("express");

//部署服务器
var app = express();
app.use(express.static("G:\MyWebs")).listen(3333);

代码的意思是使用express提供的方法来部署服务器。

static()函数里面的字符串是网站的路径名,好像相对路径的办法行不通;listen()函数里面是端口号。

2.3 访问

 然后就可以通过REPL打开js文件来部署服务器啦,部署在本地服务器上,域名为localhost或者127.0.0.1,在后面加上端口号就可以访问啦。

https://localhost:3333/
https://127.0.0.1:3333/

3 获取本地IP地址

参考资料:

nodejs官方API的os.networkInterfaces()

iteye用户zhangyaochun的博客

 在局域网内供他人访问,首先要获取自己的IP地址,除了传统的ipconfig命令手动获取添加外,我们有必要考虑如何让nodejs自动获取主机的IP地址。

 这里借用nodejs自带的os模块里面的os.networkInterfaces()方法来获取本地连接接口,os就是operation system操作系统模块。

3.1 编写获取IPv4的函数

 编写函数getLocalIPv4()函数,返回当前主机在网络连接中的IPv4地址:

//获取IPv4地址
function getLocalIPv4(){
    interfaces = require("os").networkInterfaces();

    for(var devName in interfaces){//遍历所有连接
        var iface = interfaces[devName];
        for(var i=0; i<iface.length; i++){//遍历每个连接中的不同地址(family为标识)
            var alias = iface[i];
            if(alias.family == 'IPv4'&&alias.address != '127.0.0.1'&&!alias.internal)//该判断保证为有效的IPv4地址(排除了内部地址和本地地址)
            {
                return alias.address;
            }
        }
    }

}
var ipv4 = getLocalIPv4();

3.2 函数思路解析

函数的思路如下:

  1. 首先我们用os.networkInterfaces()获取对象,这个对象具体是啥我也不知道(直接输出devName的话是“无线网络连接”、“Loopback Pseudo-Interface 1”这种鬼东西,好像后者即使没有联网也可以获取,类似于主机对外接口之类的东西吧),所以用devName对其进行遍历,然后通过devName作为索引来反向访问获取到的东西(聪明);
  2. 通过连接名获取连接后,类似于ipconfig得到的连接样式,一个连接下面有IPv4、IPv6等各种各样的连接,这时候就要遍历这些IPv4、IPv6……通过family这个关键字来判断,然后排除掉内部连接和本地连接后,能进入if条件句的就是货真价实的IPv4了。

3.3 官方API对networkInterfaces()的解释

最后我们明确一下os.networkInterfaces()获取到的究竟是个什么东西(前方大量抄袭!),官方API告诉我们,获取到的是一个对象(Object),其数据结构如下:

{
  lo: [
    {
      address: '127.0.0.1',
      netmask: '255.0.0.0',
      family: 'IPv4',
      mac: '00:00:00:00:00:00',
      internal: true,
      cidr: '127.0.0.1/8'
    },
    {
      address: '::1',
      netmask: 'ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff',
      family: 'IPv6',
      mac: '00:00:00:00:00:00',
      internal: true,
      cidr: '::1/128'
    }
  ],
  eth0: [
    {
      address: '192.168.1.108',
      netmask: '255.255.255.0',
      family: 'IPv4',
      mac: '01:02:03:0a:0b:0c',
      internal: false,
      cidr: '192.168.1.108/24'
    },
    {
      address: 'fe80::a00:27ff:fe4e:66a1',
      netmask: 'ffff:ffff:ffff:ffff::',
      family: 'IPv6',
      mac: '01:02:03:0a:0b:0c',
      internal: false,
      cidr: 'fe80::a00:27ff:fe4e:66a1/64'
    }
  ]
}

lo是内部地址,eth0是外部地址。

  • address<string> The assigned IPv4 or IPv6 address
  • netmask<string> The IPv4 or IPv6 network mask
  • family<string> Either IPv4 or IPv6
  • mac<string> The MAC address of the network interface
  • internal<boolean>true if the network interface is a loopback or similar interface that is not remotely accessible; otherwise false
  • scopeid<number> The numeric IPv6 scope ID (only specified when family is IPv6)
  • cidr<string> The assigned IPv4 or IPv6 address with the routing prefix in CIDR notation. If the netmask is invalid, this property is set to null