二、创建 Web 服务器

要开始将 Arduino 连接到 web,对 Web 技术有一个基本的了解是很有用的。本章将介绍一些原理,包括什么是 web 服务器,URL 是如何构造的,什么是路由,什么是 Node.js。然后它将变得实用,您将学习如何用 Node.js 创建一个 web 服务器,并从服务器向网页来回发送数据。它将涵盖 Node.js、ejs 和 socket.io。

什么是 Web 服务器?

web 服务器向 web 浏览器提供页面;它还处理信息并存储页面的数据和素材。它允许使用超文本传输协议(HTTP)处理请求。此协议允许网络使用称为统一资源定位符(URL)的地址(指向您的网页的地址)相互通信。URL 有一个定义好的结构,以协议开头,后面是域名、域扩展名以及可选的文件和文件夹名;见图 2-1

A453258_1_En_2_Fig1_HTML.jpg

图 2-1

URL structure

域名是互联网协议(IP)地址的自然英语翻译。IP 地址是一系列数字,任何连接到互联网的东西都有一个 IP 地址。这包括智能手机和智能电视;任何连接到互联网的设备都会有一个 IP 地址。

当互联网上的计算机相互通信时,它们使用它们的 IP 地址。当你在浏览器中输入网址时,它会被转换成 IP 地址。这将告诉 web 服务器您想要的页面的地址。这是到那个页面的路径。如果服务器找到这个页面,它会把它返回给你的浏览器。如果不能,它将返回一个错误页面。

Web 服务器有许多惯例来连接网络上的一台计算机并向另一台计算机传输数据。其中之一就是代表性状态转移,也就是 RESTful。它使计算机系统具有互操作性;这意味着,无论服务器如何设置,如果它实现了 RESTful web 服务,它就可以与任何其他也实现它们的服务器对话。当 HTTP 使用 RESTful 时,可以使用 GET、POST、PUT 和 DELETE 请求。例如,POST 允许您在网页上填写表单,并将其发送到浏览器。

您可以在自己的计算机上创建 web 服务器,使用 Node.js 就是一种方法。这意味着您可以在本地机器上开发应用程序,并在部署之前进行测试。本地 web 服务器使用域名 localhost,该域名解析为 IP 地址 127.0.0.1。

选择途径

如果没有路由,您将无法查看网页。路由决定了 web 服务器如何响应来自 web 浏览器的 URL 请求。回到 example.com,当有人输入 URL 时,服务器必须知道服务哪个页面。如果您添加到其他网页,如 example.com/about,将必须有一个在服务器上为这个网页的路线。路由还告诉服务器应该如何响应请求。它使用 RESTful 命令做到这一点;如果一个路由以 GET 开始,服务器知道它需要获取页面的内容。如果它以 POST 开始,服务器知道它将从网页接收数据,并且路由将定义下一步应该做什么。

Node.js 是什么?

Node.js 是用于执行 JavaScript 服务器代码的运行时环境。这意味着你可以在浏览器和服务器上使用同一种语言,JavaScript。使用 Node.js,您可以创建到网页的路由、连接到本地主机、连接到数据库,以及用 JavaScript 向网页发送数据。它允许你使用相同的语言构建 web 应用程序。

Node.js 与 Arduinos 配合得非常好。使用串行端口,您可以使用服务器将数据从 Arduino 传递到网页,并将数据从网页传递到 Arduino。

除了下载 Node.js 之外,您还需要下载其他软件包,以便更简单地创建您想要的应用程序。您可以使用包管理器来完成这项工作;有几个不同的,但本书使用的是节点包管理器(npm)。

使用命令行界面

命令行界面是一种使用文本向计算机发送指令的方式。你可以用它做很多事情,包括移动你的电脑目录,创建新文件和运行代码。

要使用 Node.js,您需要使用命令行界面。您可以使用它来安装新模块、启动服务器,以及查看来自应用程序的消息和错误。

Windows 和 Mac 都有内置的命令行界面应用程序。在 Windows 中它被称为命令提示符或 cmd.exe,在 Mac 中它被称为终端。两者都将打开一个控制台窗口,用于输入命令。

这是一个非常强大的工具,需要谨慎使用,因为你可以清除你的系统或做出难以撤销的更改。

命令行界面在所谓的命令行 shell 中实现。shell 是一个程序,它接受文本命令并将它们翻译成操作系统能够理解的语言。

当您打开控制台窗口时,它应该显示登录用户的主目录。这是该用户的顶层目录,您可以从中导航到该用户的文件和文件夹。

Using The Mac Terminal

Mac 终端应用程序位于应用程序文件夹内的“实用工具”文件夹中。它的路径如下:

硬盘驱动器/应用程序/实用程序/终端

当应用程序打开时,您应该会看到一个控制台窗口,显示您的主目录,后跟$:例如:~ $

尝试以下命令并查看表 2-1 中您可能会发现有用的其他命令:

表 2-1

Some useful terminal Commands

| 命令 | 结果 | | :-- | :-- | | 显示当前工作目录 | 写入当前目录的完整路径 | | 限位开关(Limit Switch) | 列出目录的内容 | | cd | 下一级目录的路径 | | cd / | 2 层以下目录的路径 | | 激光唱片.. | 上移一个目录 | | 激光唱片 | 移回主目录 | | mkdir〔t0〕 | 将在当前目录下创建一个新目录 | | 触摸 | 将使用该名称和扩展名创建一个新文件 |

  1. 打开终端,一个新的控制台窗口将会打开。
  2. 键入 ls + return,您将看到当前目录下所有文件和文件夹的列表。
  3. 键入 cd + return,您将进入该目录。
  4. 使用 ls 列出文件和目录,然后键入 cd 和目录名以移动到另一个目录。
  5. cd 标牌..+ return,您将在目录中上移一个文件夹。
  6. 键入 cd + return,您将移动到您的主目录。
  7. 键入 Ctrl + l 或 Cmd+k,这两个键都会清除控制台屏幕。Crtl+l 只是清空屏幕,Cmd+k 也是清空终端缓冲区。

Using The Windows Command Prompt

windows 控制台被称为命令提示符或 cmd.exe。有多种方法可以打开命令提示符控制台窗口,这些方法会根据您运行的 windows 版本而变化(参见表 2-2 )。您可以使用 Windows 搜索来查找命令提示符;搜索的是 Windows 10 上的 Cortana。开始在搜索栏中键入“命令提示符”;最匹配的应该是桌面应用“命令提示符”单击“命令提示符”打开控制台窗口。

当应用程序打开时,您应该会看到一个控制台窗口,显示您的主目录,后面跟着一个>应该是这样的:C:\Users\Username >,您开始在>后面键入。

尝试几个命令:

  1. 打开命令提示符,将会打开一个新的控制台窗口。
  2. 键入 dir + enter,您应该会看到当前目录中的所有文件和文件夹。
  3. 键入 cd + enter,你将进入那个文件夹。
  4. 使用 ls 列出文件和目录,使用 cd 移动到另一个目录。
  5. cd 标牌..+ enter,您将在目录中上移一个文件夹。
  6. 键入 cd %userprofile% + enter 返回主目录。
  7. 键入 cls + enter,控制台屏幕将被清除。

命令中可以有可选参数。如果您使用 dir 命令,您将看到目录中每个文件或文件夹的大量信息。如果您只想查看姓名,您可以键入 dir /b。

表 2-2

Some useful command prompt commands

| 命令 | 结果 | | :-- | :-- | | echo %cd% | 写入当前目录 dir 的完整路径 | | cd <directory name> | 当前目录下一级目录的路径 | | cd <directory name>/<directory name> | 当前目录下第二层目录的路径 | | cd .. | 上移一个目录 | | cd | 移回主目录 | | mkdir <directory name> | 将在当前目录下创建一个新目录 | | NUL> <filename.extension> | 将使用该名称和扩展名创建一个新文件 |

注意:如果您开始在控制台窗口中输入一个目录名,然后按 tab 键,目录名的其余部分将会自动填写,只要它是唯一包含这些字母的目录。

要向后或向前移动到上一个命令,请使用键盘上的上下箭头。

Mac 控制台区分大小写。Mac 控制台对空白敏感。

设置 Node.js 服务器

现在背景已经覆盖了,是时候开始编码了。如果您的计算机上没有安装 Node.js,您需要将它与节点包管理器一起安装。根据你已经在电脑上安装了什么,这可能需要一些时间,但一旦完成,进一步下载会快得多。

安装 Node.js

首先,如果您不确定您的计算机上是否安装了 Node.js,您可以在控制台窗口中检查。

Check If Node.js Is Installed

  1. 打开控制台窗口。
  2. 在控制台提示符下键入 node -v,如果安装了 Node.js,您应该会看到您的版本号(例如,v6.10.3)。
  3. 在控制台提示符下键入 npm -v,如果安装了 npm,您应该会看到版本号(例如,3.10.10)。

如果您看到版本号,请跳过安装 Node.js 的下一步,直接进入“创建应用程序”一节。

Install Node.js On Windows

在 Windows 中,您可以直接从 Node.js 网站安装 Node.js。

  1. 前往 https://nodejs.org/en/
  2. 下载 Windows 版本(x64)。为了这本书,我下载了 v6.10.3.LTS。msi)。
  3. 运行安装程序;为此:
    1. 双击下载的文件;它应该位于您的下载文件夹中,名称类似于 node-v6.10.3.x64。
    2. 安装程序窗口应该出现“按下运行按钮,这将打开 Node.js 安装向导,然后按下一步按钮。
    3. 将出现许可协议,您需要同意安装 Node.js 的许可。如果同意,请选中复选框并按下一步按钮。
    4. 您可以通过按下 next 按钮接受默认设置,直到您看到 finish 按钮,默认设置会将 Node.js 安装到一个默认目录。
    5. 按“完成”按钮完成安装。 
  4. 出现提示时,让应用程序对您的设备进行更改。
  5. 重新启动计算机。
  6. 按照上面“检查是否安装了 Node.js”一节中的说明,检查 node.js 和 npm 是否已安装。

Install Node.js On a Mac

在 Mac 上,有多种方法可以安装 Node.js。最简单的方法是从 Node.js 网站下载应用程序。虽然这是最简单的方法,但它也有缺点。它安装 Node.js 的方式意味着您可能需要管理员权限来安装补充模块和库。您可以在 install 命令之前使用 sudo 命令安装这些模块和库。sudo 命令为您提供了该安装的管理员权限。sudo 代表超级用户 do,用于 UNIX 风格的操作系统。这允许您以管理员用户的身份安装软件包。

使用 sudo 并不是最佳实践,因为拥有管理员权限意味着您可以对您的计算机进行不必要的更改。使用 sudo 还会影响一些模块的工作方式。

另一种安装 Node.js 的方法是使用节点版本管理器(NVM);它安装它,所以你不需要管理员权限来安装其他模块和库。安装起来稍微困难一些,因为你需要安装 Xcode,还需要一个. bashprofile 文件。还有一个好处:可以很容易地在 Node.js 的不同版本之间进行切换。

从 Node.js 网站安装 Node.js

如果以这种方式安装 Node.js,当您为应用程序安装新模块时可能会出现错误,并且它们不会下载。如果发生这种情况,您需要以管理员权限重新安装该模块。为此,您可以在 install 命令前键入 sudo。然后会提示您输入密码。

  1. 前往 https://nodejs.org/en/
  2. 下载 macOS 版本(x64);为了这本书,我下载了 v6.10.3.LTS。pkg)。
  3. 运行安装程序并遵循它的请求,让它安装在默认目录下。
  4. 让应用程序对您的设备进行更改。
  5. 重新启动计算机。
  6. 检查 Node.js 和 npm 是否已安装。

使用节点版本管理器(NVM)安装 Node.js

要安装 NVM,您需要在 Mac 上安装 Xcode 和. bashprofile。

如果没有安装 Xcode,从 app store 安装;这可能需要几个小时。

  1. 打开一个终端窗口,确保你是在根目录~ $如果不是在提示符下键入 cd。
  2. 请检查您是否有. bashprofile 文件。在$提示符下,键入 open -a TextEdit.app。bash_profile,如果您有一个. bashprofile,它将打开,或者您可以关闭该文件。
  3. 如果在提示符下没有. bash_profile,请键入 touch。bash_profile。
  4. 要在控制台提示符下安装 NVM,请键入:curl https://raw.githubusercontent.com/creationix/nvm/v0.25.0/install.sh | bash。
  5. 要安装 Node.js 的最新稳定版本,请在提示符下键入 nvm install stable。
  6. 在提示符下,键入 nvm 使用节点。
  7. 在 Node.js 上安装本书中使用的版本,在提示符下键入 nvm install 6.11.0。
  8. 打开控制台窗口时,将 6.11.0 版设为默认版本。在提示符下,键入 nvm 别名默认值 6.11.0。
  9. 开始使用这个版本的 Node.js,并在提示符下键入 nvm use 6.11.0。
  10. 可以看到已经安装的 Node.js 的版本:type nvm ls。
  11. 检查 Node.js 和 npm 是否已安装。

你可以在 github 页面https://github . com/creation IX/nvm找到更多关于 nvm 以及如何使用它的信息。

创建 Node.js 应用程序

到本章结束时,你将已经构建了一个使用 socket.io 从服务器向连接的浏览器发送更新的小应用程序。您将通过一系列的步骤来完成这一过程,包括创建 web 服务器、创建到 web 页面的路由、web 页面的一些基本样式,以及将数据从服务器发送到浏览器。您将以两种不同的方式从服务器发送数据:首先通过 route 函数发送到网页,然后使用 web 套接字。

要编写和编辑代码,你需要一个专门的文本编辑器。这可以是源代码编辑器或集成开发环境(IDE)。它们很容易下载和安装。有许多可用的代码,如 Sublime Text、Atom 和 Visual Studio 代码。

您需要做的第一件事是为应用程序创建目录。我调用了我的 chapter_02,所以这将是应用程序的名称。

Create The Application Directory

  1. 打开控制台窗口。
  2. 在终端键入 cd / / ,移动到你想要存储项目的目录。
  3. 在终端类型 mkdir 中为项目创建一个新文件夹。
  4. 移入新目录,在终端键入 cd 。

目录结构

当你创建一个 web 应用程序时,你需要一个目录结构。应用程序的主文件夹将是应用程序的根目录。与应用程序相关的所有其他文件和文件夹都应该在该文件夹中。组成应用程序的文件将引用此结构中的文件和文件夹。您将创建其中的一些文件和文件夹,其他文件和文件夹将在初始设置或下载模块时自动创建。

2-2 显示了本章的目录结构。package.json 文件将在安装时创建,节点模块文件夹将在您下载新模块时自动创建。“/”字符代表应用程序的根。

A453258_1_En_2_Fig2_HTML.jpg

图 2-2

The directory structure for the application Using NPM Init To Create An Application

npm 代表节点程序包管理器。它承载了成千上万的可重用代码包,您可以下载并在项目中使用。

npm 还有一个名为 npm init 的命令,这是一种创建 Node.js 应用程序的有用方法。它将询问一系列问题,然后创建一个 package.json 文件。您可以随时按 Ctrl+C 退出该过程。

使用 npm 很容易创建 Node.js 服务器的框架:

  1. 打开控制台窗口。
  2. 导航到您将用于应用程序的文件夹。
  3. 在控制台提示符下,键入 npm init+enter。
  4. 更改默认答案或按 enter 键接受它们。保持默认入口点为 index.js。
  5. 在代码编辑器中打开项目文件夹。打开应用程序的根文件夹,因为您希望能够看到连接到项目的所有文件和文件夹。此时,您应该会看到一个文件 package.json。

2-3 显示了一个 package.json 文件的例子。

package.json 是一个重要的文件,它保存应用程序的元数据,并用于处理应用程序的依赖关系。当您开始安装库时,package.json 文件中会有对它们的引用。如果您共享您的应用程序文件,您不会包括所有的库文件。因为 package.json 有对它们的引用,所以可以使用 npm install 在复制的位置安装它们。

A453258_1_En_2_Fig3_HTML.jpg

图 2-3

An example of a package.json file

请注意,名称必须是小写字母,没有空格,但您可以使用下划线和破折号。

Create A Node.js Server

在 Node.js 中,创建一个启动服务器的 JavaScript 文件。它存储在项目的根目录中,并将成为应用程序的入口点。这个文件通常被称为 app.js 或 index.js。当我使用 npm init 创建 package.json 时,我保留了 index.js 条目脚本的默认值,因此现在需要创建 index.js 文件。

在应用程序的根目录下创建一个名为 index.js 的新文件。确保您位于与 package.json 相同级别的应用程序目录中。

在新创建的 index.js 文件中,写入清单 2-1 中的以下代码。

var http = require('http');
var express = require('express');
var app = express();
var server = http.createServer(app);
server.listen(3000, function() {
  console.log('Listening on port 3000...');
});
Listing 2-1
index.js code

清单 2-1 显示了使用 Express.js 设置 web 服务器的基本代码。Express.js 不是 Node.js 库的一部分,所以必须马上安装,但首先我将解释表 2-3 中的代码。

代码解释

服务器所需的模块(如 Express.js)被加载到页面顶部,并分配给变量。JavaScript 使用 var 关键字创建变量。

表 2-3

index.js code explained

| var http = require('http'); | 这一行将 HTTP 接口引入应用程序;这允许服务器通过 HTTP 协议与浏览器通信。 | | :-- | :-- | | var express = require('express'); | 这包括我们将用来创建服务器和路由的 express 框架。Express 附带了许多功能,使设置节点服务器变得更加容易。它不是 Node.js 库的一部分,因此需要安装。 | | var app = express(); | 调用 express 应用程序,返回值放在一个变量中。这包含一个新的 express 应用程序。 | | var server = http.createServer(app); | 这将创建一个服务器对象,在发出服务器请求时调用该对象。 | | server.listen(3000, function() { }); | 这告诉服务器在端口 3000 上监听对服务器的请求。 | | console.log('Listening on port 3000...'); | console.log 是一个将消息输出到控制台的 JavaScript 函数。这里用它来告诉你服务器正在运行。 |

Using NPM To Install Libraries

此时,如果运行这段代码,就会出现错误。它使用一个名为 Express.js 的外部库,该库不属于 node . js。express . js 使得创建 web 服务器变得容易得多。需要下载它,并在 package.json 中保存对它的引用。

  1. 打开一个控制台窗口,并确保您与 package.json 文件位于同一目录中。
  2. 在命令行中键入 NPM install express @ 4 . 15 . 3-save+enter。
  3. 下载完成后,启动服务器。在控制台中,确保您位于应用程序的根目录,与 index.js 处于同一级别。

如果您在 Mac 上安装 Express.js 时遇到错误,可能是因为您需要管理员权限来安装它。尝试再次安装,这次键入 sudo NPM install express @ 4 . 15 . 3-save,然后在密码提示符下键入计算机的密码。

在控制台中,您现在应该看到监听端口 3000 的控制台日志。

如果您使用的是 Windows,您可能会看到一条安全警报,提示 Windows 防火墙已阻止此应用的某些功能。勾选表示私有网络的方框,如我的家庭或工作网络。

如果您打开 web 浏览器并键入 localhost:3000,您应该会看到:无法获取/

这是因为还没有路由,所以服务器不知道将哪个页面提供给浏览器。您将在一分钟内创建路线。

如果您查看您的应用程序目录,您会看到有一个名为节点模块的新文件夹。这是第一次在应用程序中安装新库时创建的。如果你往里面看,你会看到 Express.js 的文件和文件夹都在里面。

注意使用- save 在 package.json 文件中保存对下载模块的引用。

在本书中,我将使用@来安装新模块。这意味着你将安装我一直在使用的相同版本。没有@它将安装最新的模块。

Creating a Route To a Web Page

使用清单 2-1 中的代码,创建一个将一些文本发送到网页的简单路由,将以下粗体命令添加到您的文件中,这些命令在表 2-4 中有进一步的描述:

var http = require('http');
var express = require('express');
var app = express();
var server = http.createServer(app);

app.get('/', function (req, res) {

  res.send("Hi There!");

});

server.listen(3000, function() {
  console.log('Listening on port 3000...');
});

代码解释

现在,如果您重新启动服务器,您应该会在网页上看到文本 Hi。

表 2-4

index.js code explained

| app.get('/', function (req, res) {``res.send('Hi There!');T2】 | 函数 app.get 创建一个到应用程序根目录的路径。/'表示根,它将是主 URL,或者在本例中是 localhost:3000。如果您想将消息发送到不同的网页,例如,发送到 about 页面,您可以使用 app.get('/about ',function (req,res)。 |

  1. 键入 Ctlr+c 停止服务器。
  2. 在终端中再次键入 node index.js 来重启服务器。
  3. 刷新 web 浏览器。

添加第二个应用程序。转到第一个应用程序下面。转到清单 2-1 中的代码。

app.get('/about', function (req, res) {
  res.send("this is an about page");
});

现在您需要重新启动服务器,以便它选择新的路由:

  1. 按 Ctlr+c 停止服务器。
  2. 在终端中再次键入 node index.js 来重启服务器。
  3. 刷新 web 浏览器并转到 localhost:3000/about。

现在,您应该会在网页上看到“这是一个关于页面”的字样。您可以删除关于路线。

NodeMon(节点名)

每次对服务器进行更改时,您都必须停止并重新启动服务器,以使更改生效。有一个很有用的库叫做 nodemon,它会注意到你对它正在监视的文件的修改,并为你重启服务器。在控制台窗口中使用它很容易安装。它应该全局安装,以便所有 Node.js 应用程序都可以访问它。

Installing Nodemon

  1. 打开一个控制台窗口,并确保您在主目录;您可以在 Mac 上通过键入 cd 转到主目录,在 Windows pc 上通过键入 cd %userprofile%转到主目录
  2. 在提示符下键入 npm install nodemon -g (-g 全局安装)。
  3. 在控制台中,导航到 chapter_02 应用程序的根目录,使用 cd 命令执行此操作,例如 cd Documents/code/chapter_02
  4. 当您在控制台中位于 Node.js 应用程序的根目录时,通过键入 nodemon 并按 enter 键启动服务器。

现在,如果您对 index.js 文件进行了更改,您可以刷新浏览器并查看更新。Nodemon 自动启动 package.json 中列出的主 JavaScript 文件。

您不需要将它保存到 package.json,因为它不是您的应用程序的一部分;它是开发应用程序时的助手。

创建网页

到目前为止,您已经将数据发送到 web 浏览器,但它只是从路由器打印出一条消息。现在你需要创建一个网页。通常网页是在带有。html 扩展。这些是静态网页。因为您将使用来自服务器的数据更新页面,所以需要创建一个可以接受这些数据的动态页面。

一种方法是为。html 页面向服务器发出 AJAX 请求,然后服务器返回一些数据。这依赖于浏览器页面向服务器请求数据。

另一种更有效的方法是让服务器用它拥有的数据更新网页。在 Node.js 中,这是通过模板引擎完成的。

模板引擎

模板引擎允许您在整个网页中创建变量,服务器可以更新这些变量,而无需网页发出请求。在本书的后面,我们将把数据从 Arduino 传递到服务器。由于网页将使用模板引擎创建,因此该页面将使用新数据自动更新。

有许多不同的模板引擎可以使用,其中一些我已经在附录 b 中列出了。

Set Up The Server

要使用 ejs,需要将一些代码添加到 index.js 文件中,但是首先要将 ejs 添加到项目中:

  1. 打开控制台窗口并导航到应用程序目录的根目录,或者导航到应用程序目录的根目录。或者,如果服务器在应用程序的根目录下运行,请按 Ctlr + c 停止它。
  2. 在应用程序根目录下的控制台提示符处,键入 npm install ejs@2.5.6 - save + enter。

现在,您应该能够在 package.json 文件中看到 ejs 了。在项目中包含 ejs 只是一行代码。用粗体代码行更新 index.js 文件(清单 2-1 ):

var http = require('http');
var express = require('express');
var app = express();
var server = http.createServer(app);

app.set('view engine', 'ejs');

app.get('/', function (req, res) {
  res.send('Hi There!')
});

server.listen(3000, function() {
  console.log('Listening on port 3000...');
});

这一行新代码将允许您在项目中使用 ejs。

到目前为止,你已经在 route 中使用了 res.send。在 route 中使用 res.send 允许你发送简单的数据到一个网页,但是对于大多数应用程序来说,你希望能够发送包含更多信息的页面。为此,您可以使用函数 res.render 这允许您指定将在浏览器中呈现的文件,并向其发送新数据。

将 index.js 文件从代码(清单 2-1 )更改为粗体代码;这添加了几个变量并更改了路由,因此它使用 res.render 而不是 res.send:

....

app.set('view engine', 'ejs');

var title = "Some Arduino components starting with p"

var componentArray = ['potentiometer', 'piezo', 'phototransistor', 'pushbutton'];

app.get('/', function (req, res) {

    res.render('index', {
                title: title,
                components: componentArray
    });

});

server.listen(3000, function() {
  console.log('Listening on port 3000...');
});

代码解释

新代码从两个变量开始,这两个变量保存要传递给浏览器的数据(见表 2-5 )。

  1. 在应用程序路由处启动服务器。确保您与 index.js 文件位于同一个文件夹中。在控制台提示符下,键入 nodemon。
  2. 刷新您的网页,您应该会看到一个错误。

表 2-5

index.js code explained

| var title = "Some Arduino components starting with p" | title 变量保存一些文本。在 JavaScript 中,字符串被" "或" "包围。 | | :-- | :-- | | var componentArray = ['potentiometer', 'piezo', 'phototransistor', 'pushbutton']; | 在 JavaScript 中,[ ]用于创建数组。数组是数据的集合,可以通过其在数组中的索引(位置)来访问。componentArray 是一个由四个都是字符串的元素组成的数组。JavaScript 数组中的索引从 0 开始。要访问数组的第一个元素,可以使用 componentArray[0],这将返回字符串电位计。componentArray[3]将返回字符串按钮。 | | res.render('index', {``title: title,``components: componentArrayT3】 | 现在不是呈现一个字符串,而是告诉 Node.js 你想要呈现哪个页面。在这种情况下,它是 index.js 文件。然后列出要传递给页面的数据,在本例中是 title 和 componentArray。 |

您应该会在页面和控制台窗口中看到如下所示的错误:

错误:无法在视图目录“/Users/indie/Documents/web/book/chapter 2/03 _ set-up-ejs/views”中查找视图“索引”

这是因为现在你要求它找到一个不存在的索引页。

Set Up The Web Page

ejs 页面看起来与 html 页面相似,只是它使用了。您可以将来自服务器的 ejs 页面数据作为变量传递。在页面上,您仍然使用相同的 html 标记,但是您也可以使用 ejs 语法。用 ejs 创建的页面需要放在一个名为 views 的文件夹中。

  1. 在应用程序的根目录下,创建一个名为 views 的新文件夹。
  2. 在 views 文件夹中创建一个名为 index.ejs 的新文件。要在控制台窗口中执行此操作,请执行以下操作:
    1. 在应用程序类型 cd 视图的根
    2. 在 Mac 上键入 touch index.ejs
    3. 我们有 Windows pc 类型 nul > index。例如 

在 Windows 中,您可能会得到拒绝访问的控制台响应,但文件应该已经创建。

在新创建的 index.ejs 文件中,写入清单 2-2 中的代码。

<!DOCTYPE html>
<html>
<head>
    <title>an ejs page</title>
</head>
<body>
    <h1>EJS</h1>
    <p>This page is an ejs page and will show data from the server</p>
</body>
</html>
Listing 2-2index.ejs code

在控制台窗口中,确保您位于项目的根目录,并重新启动服务器。在浏览器上,转到 http://localhost:3000/现在,您应该可以在网页上看到文本。您用一些简单的 HTML 创建了这个页面。HTML 代表超文本标记语言,是用于创建网页的通用标记语言。我将在第 4 章中更详细地介绍 HTML。它列出了页面的结构和其中的元素。

Adding Data To The Web Page

服务器已经将来自 res.render 的数据传递给了浏览器。它传递了一个名为 title 的字符串,其中包含文本“一些以 P 开头的 Arduino 组件”和一个名为 components 的数组,其中包含['potentiometer ',' piezo ',' photo tomy ',' pushbutton']。使用 ejs,浏览器现在可以访问这些数据。

用粗体文本更新清单 2-2 中的 index.ejs:

<!DOCTYPE html>
<head>
    <title>an ejs page</title>
</head>
<body>
    <h1>EJS</h1>
    <p>This page is an ejs page and will show data from the server</p>

    <h2><%= title %></h2>
    <% components.forEach(function(component) { %>
        <p>component: <%= component %> </p>
    <% }); %>

</body>
</html>

代码解释

,或者是 ejs 库的一部分。

在你写 JavaScript 的时候使用标签,它会在标签里面运行 JavaScript,文本不会出现在页面上。通常,当你想在网页上添加 JavaScript 时,你必须将它封装在脚本标签中,稍后你会用到。EJS 有自己版本的脚本标签,当您编写代码来访问从服务器传来的数据时,可以使用它。

当标签被使用时,它们里面的内容就会出现在页面上。在标签内部,您可以引用从服务器传递到浏览器的变量,并在网页上看到它。参见表 2-6

表 2-6

index.ejs code explained

| <h2><%= title %></h2> | 标题是从服务器传递的数据的一部分。如你想看标题你用。您可以将 EJS 包装在任何您喜欢的 HTML 标签中。在这种情况下,ejs 被包装在一个 H2 标签中。 | | :-- | :-- | | 组件: | 它使用一个 JavaScript forEach 函数来迭代从服务器传来的数组数据,并写出数组的每个元素。 |

Adding CSS

CSS 代表级联样式表,它用于设计网页上的元素。一个没有 CSS 的网页看起来很基础。虽然 CSS 可以添加到。最佳实践是创建一个单独的。保存样式的 CSS 文件。然后,您需要一个到。中的 css 文件。ejs 页面。

在 web 应用程序中,有一些称为静态文件的文件,它们不是由服务器创建的,而是在网页上使用的。这些文件包括 CSS 文件、图像和 JavaScript 文件。要在. ejs 文件中使用它们,您需要知道从静态文件到。ejs 文件。Express.js 有一个名为 express.static 的中间件函数来帮助解决这个问题。您在应用程序的根目录下创建一个文件夹来保存所有静态文件;该文件夹通常称为公共文件夹。在 index.js 文件中,express.static 函数用于注册公共文件夹。这意味着。ejs 将这个文件夹识别为静态文件的根文件夹,您不必将的绝对路径写到。当你调用 css 文件时。你会写出这样的东西:<link href="/css/main.css" rel="stylesheet" type="text/css">

要将 CSS 添加到页面中,首先创建一个静态文件夹。

  1. 在应用程序的根目录下,创建一个名为 public 的新文件夹。
  2. 在这个文件夹中创建另一个名为 css 的文件夹。
  3. 在 css 文件夹中创建一个名为 main.css 的文件。
  4. 用下面的更新代码更新 index.js 文件,使其包含静态函数。

现在用粗体代码更新清单 2-1 中的 index.js 文件:

...

app.set('view engine', 'ejs');

app.use(express.static(__dirname + '/public'));

var title = "Some Arduino components starting with P"
var componentArray = ['potentiometer', 'piezo', 'phototransistor', 'pushbutton'];

...
server.listen(3000, function() {
  console.log('Listening on port 3000...');
});

代码解释

注册静态文件文件夹需要一行代码(表 2-7 )。

表 2-7

index.js code explained

| app.use(express.static(__dirname + '/public')); | 这告诉应用程序所有的静态文件都将从一个名为 public 的文件夹中提供。 |

现在打开您刚刚创建的 main.css 文件并添加到 css 中(清单 2-3 ):

*{
    margin: 0;
    padding:0;
}
body{
    background-color: #F2F3F4;
    font-family: Verdana, Arial, Helvetica, sans-serif;
}

h1, h2, p{
    padding: 10px;
}

h1{
    background-color: #4ABCAC;
    color: white;
}

#components{
    margin: 10px;
    border: #F78733 solid 2px;
    display: inline-block;
}

Listing 2-3main.css

您还需要更新 index.ejs 文件,告诉它在哪里可以找到 CSS 文件。用粗体 HTML 更新 index.ejs 文件(清单 2-2 ):

<!DOCTYPE html>
<head>
    <title>an ejs page</title>
    <link href="/css/main.css" rel="stylesheet" type="text/css">
</head>
<body>
    <h1>EJS</h1>
    <p>This page is an ejs page and will show data from the server</p>
    <h2><%= title %></h2>
    <div id="components">
        <% components.forEach(function(component) { %>
            <p>component: <%= component %> </p>
        <% }); %>
    </div>
</body>
</html>

因此,在服务器运行的情况下,刷新您的网页,您现在应该会看到新的样式;它使用 HTML 标签和一个 id 来设置内容的样式。

package.json 和版本控制

现在,您已经为您的应用程序安装了几个包,是时候再看一下 package.json 文件了。它保存了关于应用程序的信息,包括您安装的依赖项(模块)的名称及其版本号。

这些依赖关系由不同的人编写,并且在不同的时间更新。这些更新可能会破坏您的代码。语义版本控制用于跟踪变更。这意味着版本号的每个数字都有特定的含义。如图 2-4 所示,版本号由三个数字组成,用句号分隔。每个新版本的数字都会增加,每个数字代表一种不同的更新。

A453258_1_En_2_Fig4_HTML.jpg

图 2-4

Version control numbers

在 package.json 文件中,您可以看到依赖关系。

{
  "name": "set-up-routes",
  "version": "1.0.0",
  "description": "setting up simple routes",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Indira",
  "license": "ISC",
  "dependencies": {
    "ejs": "^2.5.6",
    "express": "^4.15.3"
  }
}

每个安装的模块旁边是它的版本号。您可能还会看到一个符号,如*或~。当您从 package.json 运行 npm install 时,这些符号为可以下载的版本提供了一些灵活性。

=或 v 这确保安装了完全相同版本的软件包。例如,v2.5.6 将确保下载软件包的版本 2.5.6。

~这修复了主要版本和次要版本,但允许更高的修补版本。例如,2.5.6 将确保安装的版本高于或等于 2.5.6,但低于 2.6.0。

^这修复了主要版本号,但允许不同的次要或修补版本。例如,^2.5.6 将确保已安装的版本可以大于或等于 2.5.6 且小于 3.0.0。

这是一个通配符,表示可以安装任何版本。比如 2。表示可以安装任何以 2 开头的版本。

Setting Up a WebSocket With Socket.io

现在回到创建应用程序。此时,服务器在加载时传递网页数据。如果数据更新,网页将不会反映这种变化。您可以编写一个脚本,定期 pinged 服务器以查看是否有变化,但这不是很有效;如果没有新数据,您将会浪费调用,并且当新数据到达时,页面将不得不等到下一次调用来更新。

WebSocket 协议解决了这个问题:新数据将直接发送到网页,网页可以将数据发送回服务器,以更新连接到服务器的其他浏览器。这本书将使用 socket.io 库进行 web 套接字调用。

首先,socket.io 需要安装为 socket.io 不随 Node.js 一起安装。

  1. 打开控制台窗口,导航到应用程序的根目录。
  2. 在提示符下键入 NPM install socket . io @ 1 . 7 . 3–save。

现在,您可以将 socket.io 包含到 index.js 文件中。Index.js 将不再使用变量 title 和 componentArray 向浏览器发送数据,因此可以删除它们。app.get 函数也被更新,因此变量不再被发送到 index.ejs。更新 index.js 文件,使其与清单 2-4 中的代码匹配,新代码以粗体显示:

var http = require('http');
var express = require('express');
var app = express();
var server = http.createServer(app);

var io = require('socket.io')(server);

app.set('view engine', 'ejs');
app.use(express.static(__dirname + '/public'));

app.get('/', function (req, res) {

  res.render('index')

});

io.on('connection', function(socket){

    console.log('Connection to client established');
    socket.on('disconnect',function(){
        console.log('Server has disconnected');
    });

});

server.listen(3000, function() {
  console.log('Listening on port 3000...');
});

Listing 2-4index.js updated

代码解释

Socket.io 改变了数据传递给浏览器的方式;它不再在路由中发送,而是通过套接字发送(表 2-8 )。

表 2-8

index.js updated code explained

| var io = require('socket.io')(server); | 这段代码包含 socket.io 并将服务器附加到它上面。 | | :-- | :-- | | app.get('/', function (req, res) {``res.render('index')T2】 | 这将创建一个从服务器到 URL 根目录下的 index.ejs 页面的路由。这一次,您没有通过路由发送数据。 | | io.on('connection', function(socket){ console.log('Connection to client established'); | 当网页连接到服务器时,io.on 函数将告诉套接字做什么。每次浏览器连接到服务器时,您都会看到一个控制台日志。 | | socket.on('disconnect',function(){``console.log('Server has``disconnected');T3】 | 当浏览器断开与服务器的连接时,该功能将运行。 |

Rewrite The Index.ejs File To Include Socket.io

index.ejs 需要显示来自套接字的数据。您不再需要显示来自服务器的数据的 CSS 或许多 HTML 组件。有新的 HTML 组件将显示来自套接字的数据。套接字使用 JavaScript。index.ejs 文件中必须有一个对应的 socket 引用 index.js 中的 socket,所以 index.ejs 中必须有一个对 socket.io 的引用标签用于将 JavaScript 代码添加到 index.ejs 中(见表 2-9 )。用清单 2-5 中的代码更新 index.ejs,注意,index.ejs 以前版本中的很多代码已经被删除了。

<!DOCTYPE html>
<head>
    <title>WebSockets</title>
</head>
<body>

    <div class="wrapper">
        <h1>Using socket.io</h1>
        <p>This page will update with socket.io</p>
    </div>

<script src="https://cdn.socket.io/socket.io-1.2.0.js"></script>
<script>
    var socket = io();
</script>
</body>
</html>

Listing 2-5index.ejs

代码解释

在控制台中,确保您位于应用程序的根目录并启动应用程序。

尝试在不同的浏览器和浏览器标签上打开和关闭页面,并查看控制台。每次有到服务器的新连接时,您应该看到到客户机的连接已经建立。每次通过关闭页面来关闭到服务器的连接时,您应该会看到服务器已经断开连接。

表 2-9

index.ejs code explained

| | 在 socket.io 库中调用网页;没有这个页面就不能访问库。 | | :-- | :-- | | var socket = io(); | 为 socket.io 函数创建一个变量。 |

插座如何工作

Socket.io 有许多广播和监听数据的函数。socket.emit 广播数据,socket.on 监听数据。

这些函数在服务器和浏览器上使用一对匹配的 id。这些匹配的 id 对将相互监听更新,并相互发送数据。

其结构是:

socket.emit('an_example_id', message);

socket.on('an_ example_id', function(message){
      Do something with the message from socket.emit
});

socket.emit 将用匹配的 id 将数据发送给函数 socket.on。Socket.on 将侦听来自 socket.emit 的具有匹配 id 的数据。

这意味着您可以拥有多个具有不同 id 的套接字,并且不同套接字之间的数据不会混淆。

Sending Data To a Web Page With Socket.io

现在,您将在服务器和浏览器页面上创建一个简单的套接字,在它们之间传递信息。网页上会有一个按钮,当它被点击时会更新一个数字。按钮已被点击的消息将通过 socket.io 发送到服务器。号码将被改变,然后服务器端的 socket.io 将信息发送回连接的网页。

在 index.js 中添加粗体代码:

var http = require('http');
var express = require('express');
var app = express();
var server = http.createServer(app);
var io = require('socket.io')(server);

app.set('view engine', 'ejs');
app.use(express.static(__dirname + '/public'));

app.get('/', function (req, res) {
  res.render('index')
});

var buttonValue = 0;

io.on('connection', function(socket){
    console.log('Connection to client established');
    io.emit('clicked message', buttonValue);

    socket.on('clicked message', function(msg){
          buttonValue = 1 - buttonValue;
            io.emit('clicked message', buttonValue);
            console.log('Received message from client!',msg);
    });

socket.on('disconnect',function(){
        console.log('Server has disconnected');
    });
});

server.listen(3000, function() {
  console.log('Listening on port 3000...');
});

代码解释

2-10 分解了你刚刚添加的代码。

表 2-10

index.js code explained

| var buttonValue = 0; | 这个变量包含一个值,当有人点击浏览器上的一个按钮时,这个值就会改变。 | | :-- | :-- | | socket.on('clicked message', function(msg){``buttonValue = 1 -   buttonValue;``io.emit('clicked message', buttonValue);``console.log('Received message from client!', buttonValue);T4】 | 在这段代码中,套接字 id 是“clicked message”。此套接字将侦听由函数 io.emit('clicked message ',msg)从浏览器发送的消息。当它收到一个时,它将执行指令 button value = 1-button value;这会将 buttonValue 的值更改为零或一。然后,它将使用 io.emit('clicked message ',buttonValue)将新值发送给监听更改的 web 浏览器。 |

清单 2-5 中的 index.ejs 也需要用粗体代码进行更新:

<!DOCTYPE html>
<head>
    <title>WebSockets</title>
</head>
<body>
    <div class="wrapper">
        <h1>Using socket.io</h1>
        <p>This page will update with socket.io</p>
        <button id="clicked">click me</button>
        <div id="updates"></div>
    </div>
<script src="https://cdn.socket.io/socket.io-1.2.0.js"></script>
<script>
    var socket = io();
    var button = document.getElementById('clicked');

    button.onclick = function(e){
        socket.emit('clicked message', 'clicked');
    }
    socket.on('clicked message', function(msg){
        document.getElementById('updates').innerHTML = msg;
    });
</script>
</body>
</html>

代码解释

您现在应该有一个可以与网页交互并更新网页的工作服务器(表 2-11 )。如果你点击页面上的按钮,它将会更新,同时也会更新具有相同 URL 的其他页面;您还应该在控制台中看到一条消息。

表 2-11

index.ejs code explained

| var button = document.getElementById('clicked'); | 这行代码是一些基本的 JavaScript。在 HTML 中有一个 id 为“clicked”的按钮元素。变量按钮将保存对该元素的引用,因此可以在 JavaScript 中引用它。 | | :-- | :-- | | button.onclick = function(e){``socket.emit('clicked    message','clicked');T2】 | onclick 是当点击网页上的按钮时执行的功能。函数 socket.emit('clicked message ',' clicked ');叫做。这将把“已点击”的消息传递给服务器的对应 socket.io 函数 socket.on(“已点击的消息”)。 | | socket.on('clicked message', function(msg){document.getElementById('updates').innerHTML = msg;     }); | 这段代码监听来自服务器的 Id 为“clicked message”的消息,当它得到一个消息时,它使用 JavaScript 函数 document.getElementById 在页面上查找 id 为“updates”的元素,并将其内部 html 更改为从服务器传入的数据。 |

摘要

本章向您介绍了 web 技术,以及如何创建 web 服务器来与 web 浏览器收发数据。

在下一章中,您将使用这些技能来创建一个服务器,该服务器将从 Arduino 导入数据并在网页上显示它。