草庐IT

Express.js 笔记

risejl 2023-03-28 原文

Express

myApp.js 文件的前两行中,创建一个 Express 应用对象很简单。 这个对象有几种方法,一个基础的方法是 app.listen(port)。 它处于运行状态时告诉服务器监听指定的端口。 出于测试的原因,需要应用在后台运行,所以在 server.js 中已经添加了这个方法。

在 Express 中,路由采用这种结构:app.METHOD(PATH, HANDLER), METHOD 是 http 请求方法的小写形式, PATH 是服务器上的相对路径(它可以是一个字符串,甚至可以是正则表达式), HANDLER 是匹配路由时 Express 调用的函数, 处理函数采用这种形式:function(req, res) {...},其中 req 是请求对象,res 是响应对象, 例如:

function(req, res) {
 res.send('Response String');
} // “Response String”
app.get("/", function(req, res) {
 res.send("Hello Express");
})

提供 HTML 文件

通过 res.sendFile(path) 方法给请求响应一个文件, 可以把它放到路由处理 app.get('/', ...) 中。 在后台,这个方法会根据想发送的文件的类型,设置适当的消息头信息来告诉浏览器如何处理它, 然后读取并发送文件, 此方法需要文件的绝对路径。 建议使用 Node. js 的全局变量 __dirname 来计算出这个文件的绝对路径:

absolutePath = __dirname + relativePath/file.ext
var express = require('express');

var app = express();

let absolutePath = __dirname +  "/views/index.html";

app.get("/", function(req, res) {
 res.sendFile(absolutePath);
});

module.exports = app;

提供静态资源

HTML 服务器通常有一个或多个用户可以访问的目录。 可以将应用程序所需的静态资源 (样式表、脚本、图片) 放在那里。在 Express 中可以使用中间件 express.static(path) 来设置此功能,它的参数 path 就是包含静态资源文件的绝对路径。

其实,中间件就是一个拦截路由处理方法并在里面添加一些信息的函数。 使用 app.use(path, middlewareFunction) 方法来加载一个中间件, 它的第一个参数 path 是可选的, 如果没设置第一个参数,那么所有的请求都会经过这个中间件处理。

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

在指定路由上提供 JSON

HTML 服务器提供 HTML 服务,而 API 提供数据服务。 REST(REpresentational State Transfer)API 允许以简单的方式进行数据交换,对于客户端不必要知道服务器的细节。 客户只需要知道资源在哪里(URL),以及想执行的动作(动词)。 GET 动词常被用来获取无需修改的信息。 如今,网络上的移动数据首选格式是 JSON, 简而言之,JSON 是一种可以方便地用字符串表示 JavaScript 对象的方式,因此它很容易传输。

来创建一个简单的 API,创建一个路径为 /json 且返回数据是 JSON 格式的路由, 可以像之前那样用 app.get() 方法来做。 然后在路由处理部分使用 res.json() 方法,并传入一个对象作为参数, 这个方法会结束请求响应循环(request-response loop),然后返回数据。 在后台,它把一个有效的 JavaScript 对象转化为字符串,然后会设置适当的消息头来告诉浏览器:“这是一个 JSON 数据”,最后将数据返回给客户端。 一个有效的对象通常是这种结构:{key: data}data 可以是数字、字符串、嵌套对象或数组, data 也可以是变量或者函数返回值,在这种情况下,它们先求值再转成字符串。

app.get("/json", function(req, res) {
 res.json({
   "message": "Hello json"
});
})

当向路由 /json 发送 GET 请求,将对象 {"message": "Hello json"} 以 JSON 格式返回给客户端, 浏览器访问 your-app-url/json 时,应该在屏幕上看到这个消息。

使用 .env 文件

.env 文件是一个用于将环境变量传给应用程序的隐藏文件, 这是一个除了开发者之外没人可以访问的私密文件,它可以用来存储保密或者隐藏的数据, 例如,它可以存储第三方服务的 API 密钥或者数据库 URI, 也可以使用它来存储配置选项, 通过设置配置选项,改变应用程序的行为,而无需重写一些代码。

在应用程序中通过 process.env.VAR_NAME 访问到环境变量。 process.env 对象是 Node 程序中的一个全局对象,可以给这个变量传字符串。 习惯上,变量名全部大写,单词之间用下划线分隔。 .env 是一个 shell 文件,因此不需要用给变量名和值加引号。 还有一点需要注意,当你给变量赋值时等号两侧不能有空格,例如:VAR_NAME=value。 通常来讲,每一个变量定义会独占一行。

app.get('/json', (function(req,res)   {
 const mySecret = process.env['MESSAGE_STYLE'];
 if( mySecret === "uppercase" ){
   res.json({"message" : "Hello json".toUpperCase() });
} else {
   res.json({"message" : "Hello json" });
}

}))

添加一个环境变量作为配置选项。

在项目根目录创建一个 .env 文件,并存储变量 MESSAGE_STYLE=uppercase

当向 /json 发 GET 请求时,如果 process.env.MESSAGE_STYLE 的值为 uppercase,那么上一次挑战中的路由处理程序返回的对象的消息则应该大写。 响应对象应该是 {"message": "Hello json"} or {"message": "HELLO JSON"},取决于 MESSAGE_STYLE 的值。

注意: 在本地工作,需要 dotenv 包。 它将环境变量从的 .env 文件加载到 process.env 中。 使用 npm install dotenv 安装它。 然后,在 myApp.js 文件的顶部,使用 require('dotenv').config() 导入和加载变量。

实现一个根级的请求记录中间件 Root-Level Request Logger Middleware

中间件函数是一个接收 3 个参数的函数,这 3 个参数分别是:请求对象、响应对象和在应用的请求-响应循环中的下一个函数。 中间件函数执行一些可能对应用程序产生一些效果的代码,通常还会在请求对象或者响应对象里添加一些信息, 它们也可以在满足某些条件时通过发送响应来结束循环, 如果在它们完成时没有发送响应,那么就会开始执行堆栈中的下一个函数, next() 将触发调用第 3 个参数。

请看以下示例:

function(req, res, next) {
 console.log("I'm a middleware...");
 next();
}

假设在某个路由上安装了这个中间件函数, 当一个请求与路由匹配时,它会显示字符串“I’m a middleware…”,然后它执行堆栈中的下一个函数。可以使用 app.use(<mware-function>) 方法。 在这种情况下,该函数将对所有请求执行,但也可以设置更具体的条件来执行, 例如,如果你希望某个函数只针对 POST 请求执行,可以使用 app.post(<mware-function>) 方法。 所有的 HTTP 动词(GET、DELETE、PUT……)都存在类似的方法。

app.use(function(req, res, next) {
 console.log(req.method + " " + req.path + " - " + req.ip);
 next();
})

注意: Express 按照函数在代码中出现的顺序来执行, 中间件也是如此。 如果想让中间件函数适用于所有路由,那么应该在路由之前配置好中间件。

通过链式调用中间件来创建时间服务 Chain Middleware

使用 app.METHOD(path, middlewareFunction) 可以在指定的路由挂载中间件, 也可以在路由定义中链式调用中间件。

请看以下示例:

app.get('/user', function(req, res, next) {
 req.user = getTheUserSync();  
 next();
}, function(req, res) {
 res.send(req.user);
});

此方法可用于将服务操作拆分为较小的单元, 这可以让应用拥有更好的结构,也便于在不同的位置上复用代码; 此方法还可用于对数据执行某些验证。 可以在每一个中间件堆栈中,阻止当前链的执行,并将控制权传递给专门设计用于处理错误的函数; 或者可以将控制权传递给下一个匹配的路由,以处理特殊情况。

从客户端获取路由参数 Route Parameter

在构建 API 时,要让用户说明他们想从服务中获取什么。 举个例子,如果客户请求数据库中存储的用户信息,需要一种方法让开发者知道用户对哪个数据库用户项感兴趣, 使用路由参数可以实现这个需求。 路由参数是由斜杠(/)分隔的 URL 命名段, 每一小段能捕获与其位置匹配的 URL 部分的值, 捕获的值能够在 req.params 对象中找到。

路由地址:'/user/:userId/book/:bookId' 实际请求 URL:'/user/546/book/6754' req.params:{userId: '546', bookId: '6754'}

app.get("/:word/echo", (req, res) => {
 const { word } = req.params;
 res.json({
   echo: word
});
});

从客户端获取输入的查询数据 Query Parameter

从客户端获取输入的另一种常见方式是使用查询字符串对路由路径中的数据进行编码, 查询字符串使用标记(?)分隔,并且包含键值对 field=value, 每对键值使用连字号(&)分隔。 Express 能够从查询字符串中解析这些数据,并且把它放到 req.query 对象中。 有些字符(如百分号(%))不能在出现在 URL 中,它们在发送前必须以不同的格式进行编码。 如果使用 JavaScript 的 API,可以用特定的方法来编码/解码这些字符。

路由地址:'/library' 实际请求 URL:'/library?userId=546&bookId=6754' req.query:{userId: '546', bookId: '6754'}

注意: 在后面的练习中,我们将向相同的路由路径 /name 发送 POST 请求来接收数据。 如果愿意,可以使用app.route(path).get(handler).post(handler)这中写法, 这种语法允许在同一路径路由上链式调用不同的请求方法, 可以节省一点打字时间,也可以让代码看起来更清晰。

app.get("/name", function(req, res) {
 res.json({
   name: `${req.query.first} ${req.query.last}`
});
})

body-parser

除了 GET 还有另一个常见的 HTTP 动词,即 POST。 POST 是使用 HTML 表单发送客户端数据的默认方法。 在 REST 规范中,POST 常用于发送数据以在数据库中创建新项目(新用户或新博客文章)。 在这个项目中没有使用数据库,但下面将学习如何处理 POST 请求。

在这种类型的请求中,数据不会出现在 URL 中,而是隐藏在请求正文中。 请求正文也是 HTML 请求的一部分,被称为负载。 即使数据在 URL 中是不可见的,也不意味着它是私有的。 要了解原因,请观察 HTTP POST 请求的原始内容:

POST /path/subpath HTTP/1.0
From: john@example.com
User-Agent: someBrowser/1.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 20

name=John+Doe&age=25

正如你所看到的,正文被编码成类似查询字符串的形式, 这是 HTML 表单使用的默认格式。 可以通过 Ajax 使用 JSON 来处理具有更复杂结构的数据。 还有另一种类型的编码:multipart/form-data, 它被用来上传二进制文件。 使用 URL 编码请求正文。 要解析来自 POST 请求的数据,必须安装 body-parser 包, 这个包包含一套可以解码不同格式数据的中间件。

var express = require('express');
var bodyParser = require("body-parser");
var app = express();


app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());

从 POST 请求中获取数据

在路径 /name 挂载一个 POST 处理方法, 和前面一样, 我们已经在 html 首页准备了一份表单, 它将提交与练习 10 相同的数据(查询字符串), 如果 body-parser 正确配置好了,那么就可以在 req.body 对象中找到请求的参数。 来看看一个常规的例子:

路由:POST '/library' URL 编码的请求正文:userId=546&bookId=6754 req.body:{userId: '546', bookId: '6754'}

响应和前面一样的 JSON 对象 {name: 'firstname lastname'}。 可以使用首页应用提供的 html 表单,来测试 API 是否正常工作。

提示:除了 GET 和 POST,还有其他几种 http 方法。 按照惯例,http 动词和在服务端执行的某种操作之间有对应关系, 这种对应关系通常如下:

POST(有时候是 PUT)- 使用请求发送信息,以创建新资源;

GET - 读取不用修改的已存在的资源;

PUT 或者 PATCH(有时候是 POST)- 发送数据,以更新资源;

DELETE => 删除一个资源。

还有其他两种方法常用于与服务进行交互。 除了 GET 之外,上面列出的所有方法都可以负载数据(即数据都能放到消息正文中), 这些方法也可以使用 body-parser 中间件。

var express = require('express');
var app = express();
var bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({extended: false}));
const path = require('path')


app.post("/name", function(req, res) {
 var string = req.body.first + " " + req.body.last;
 res.json({ name: string });
});

module.exports = app;
 

有关Express.js 笔记的更多相关文章

  1. LC滤波器设计学习笔记(一)滤波电路入门 - 2

    目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称

  2. ruby-on-rails - Assets 管道损坏 : Not compiling on the fly css and js files - 2

    我开始了一个新的Rails3.2.5项目,Assets管道不再工作了。CSS和Javascript文件不再编译。这是尝试生成Assets时日志的输出:StartedGET"/assets/application.css?body=1"for127.0.0.1at2012-06-1623:59:11-0700Servedasset/application.css-200OK(0ms)[2012-06-1623:59:11]ERRORNoMethodError:undefinedmethod`each'fornil:NilClass/Users/greg/.rbenv/versions/1

  3. ruby-on-rails - Rails - 理解 application.js 和 application.css - 2

    rails新手。只是想了解\assests目录中的这两个文件。例如,application.js文件有如下行://=requirejquery//=requirejquery_ujs//=require_tree.我理解require_tree。只是将所有JS文件添加到当前目录中。根据上下文,我可以看出requirejquery添加了jQuery库。但是它从哪里得到这些jQuery库呢?我没有在我的Assets文件夹中看到任何jquery.js文件——或者直接在我的整个应用程序中没有看到任何jquery.js文件?同样,我正在按照一些说明安装TwitterBootstrap(http:

  4. node.js - 如何在 Travis CI 上的一个项目中运行 Node.js 和 Ruby 测试 - 2

    我有一个包含多个组件的存储库,其中大部分是用JavaScript(Node.js)编写的,一个是用Ruby(RubyonRails)编写的。我想要一个.travis.yml文件来触发一个运行每个组件的所有测试的构建。根据thisTravisCIGoogleGroupthread,目前还没有官方支持。我的目录结构是这样的:.├──构建服务器├──核心├──扩展├──网络应用├──流浪文件├──package.json├──.travis.yml└──生成文件我希望能够运行特定版本的Ruby(2.2.2)和Node.js(0.12.2)。我已经有了一个make目标,所以maketest在每

  5. Unity Shader 学习笔记(5)Shader变体、Shader属性定义技巧、自定义材质面板 - 2

    写在之前Shader变体、Shader属性定义技巧、自定义材质面板,这三个知识点任何一个单拿出来都是一套知识体系,不能一概而论,本文章目的在于将学习和实际工作中遇见的问题进行总结,类似于网络笔记之用,方便后续回顾查看,如有以偏概全、不祥不尽之处,还望海涵。1、Shader变体先看一段代码......Properties{ [KeywordEnum(on,off)]USL_USE_COL("IsUseColorMixTex?",int)=0 [Toggle(IS_RED_ON)]_IsRed("IsRed?",int)=0}......//中间省略,后续会有完整代码 #pragmamulti_c

  6. Tcl脚本入门笔记详解(一) - 2

    TCL脚本语言简介•TCL(ToolCommandLanguage)是一种解释执行的脚本语言(ScriptingLanguage),它提供了通用的编程能力:支持变量、过程和控制结构;同时TCL还拥有一个功能强大的固有的核心命令集。TCL经常被用于快速原型开发,脚本编程,GUI和测试等方面。•实际上包含了两个部分:一个语言和一个库。首先,Tcl是一种简单的脚本语言,主要使用于发布命令给一些互交程序如文本编辑器、调试器和shell。由于TCL的解释器是用C\C++语言的过程库实现的,因此在某种意义上我们又可以把TCL看作C库,这个库中有丰富的用于扩展TCL命令的C\C++过程和函数,所以,Tcl是

  7. node.js - 从未编写过任何自动化测试,我应该如何开始行为驱动开发? - 2

    按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭9年前。多年来,我一直在使用多种语言进行编程,并且认为自己总体上相当擅长。但是,我从未编写过任何自动化测试:没有单元测试,没有TDD,没有BDD,什么都没有。我已经尝试开始为我的项目编写适当的测试套件。我可以看到在进行任何更改后能够自动测试项目中所有代码的理论值(value)。我可以看到像RSpec和Mocha这样的测试框架应该如何使设置和运行所述测试变得相当容易

  8. ruby-on-rails - 将 Angular JS 与 Rails 集成 - 2

    我需要一些指导来了解如何将Angular整合到rails中。选择Rails的原因:我喜欢他们偏执的做事方式。还有迁移,gem真的很酷。使用angular的原因:我正在研究和寻找最适合SPA的框架。Backbone似乎太抽象了。我不得不在Angular和Ember之间做出选择。我首先开始阅读Angular,它对我来说很有意义。所以我从来没有去读过关于ember的文章。使用Angular和Rails的原因:我研究并尝试使用小型框架,例如grape、slim(是的,我也使用php)。但我觉得需要坚持项目的长期范围。我个人喜欢用Rails的方式做事。这就是我需要帮助的地方,我在Rails4中有

  9. node.js - 如何比较图像并确定哪个内容更多? - 2

    目标:我想从动画GIF中抓取最佳帧并将其用作静态预览图像。我相信最好的帧是显示最多内容的帧-不一定是第一帧或最后一帧。以这张动图为例:--这是第一帧:--这是第28帧:很明显,第28帧很好地代表了整个GIF。我如何以编程方式确定一帧是否比另一帧具有更多像素/内容?如果您能向我指出任何想法、想法、包/模块或文章,我们将不胜感激。 最佳答案 实现此目的的一种直接方法是估计entropy每个图像的帧,并选择具有最大熵的帧。在信息论中,熵可以被认为是图像的“随机性”。单一颜色的图像是非常可预测的,分布越平坦,越随机。这与Arthur-R描述

  10. 计算机网络笔记:TCP三次握手和四次挥手过程 - 2

    TCP是面向连接的协议,连接的建立和释放是每一次面向连接的通信中必不可少的过程。TCP连接的管理就是使连接的建立和释放都能正常地进行。三次握手TCP连接的建立—三次握手建立TCP连接①若主机A中运行了一个客户进程,当它需要主机B的服务时,就发起TCP连接请求,并在所发送的分段中用SYN=1表示连接请求,并产生一个随机发送序号x,如果连接成功,A将以x作为其发送序号的初始值:seq=x。主机B收到A的连接请求报文,就完成了第一次握手。客户端发送SYN=1表示连接请求客户端发送一个随机发送序号x,如果连接成功,A将以x作为其发送序号的初始值:seq=x②主机B如果同意建立连接,则向主机A发送确认报

随机推荐