express-cli入门

by Victor Ofoegbu

由Victor Ofoegbu

使用Express.js入门 (Getting off the ground with Express.js)

使用Node.js框架编写Web应用 (Writing web apps with the Node.js framework)

A common moment of truth is when you develop a lot of applications that need the same or identical functionality. It’s now obvious that copying and pasting code isn’t scalable — you need a tool that was made for flexibility, minimality, and reusability.

一个常见的现实时刻是,当您开发许多需要相同或相同功能的应用程序时。 现在很明显,复制和粘贴代码是不可扩展的—您需要一种为灵活性,最小化和可重用性而设计的工具。

That’s where Express sits in the MERN stack. It’s a Node.js framework for building scalable web applications.

这就是Express位于MERN堆栈中的位置。 这是一个用于构建可伸缩Web应用程序的Node.js框架。

In this post, we’ll go deep into building web apps with the Express framework. We’ll look at Database integration, sessions, and cookies, templating engines to solidify our workflow, and finally production and security concerns.

在本文中,我们将深入研究使用Express框架构建Web应用程序。 我们将研究数据库集成,会话和cookie,模板引擎以巩固我们的工作流程,最后是生产和安全方面的问题。

This tutorial requires you to have Node.js and npm installed, and you should possess a basic understanding of Node.js and JavaScript generally. If you aren’t familiar with Node.js, here’s my last post: The only NodeJs introduction you’ll ever need. It’s a great place to start diving into Node.js.

本教程要求您安装Node.js和npm,并且您应该对Node.js和JavaScript具有基本的了解。 如果您不熟悉Node.js,这是我的最后一篇文章: 您唯一需要的NodeJs简介 。 这是开始深入研究Node.js的好地方。

让我们做快递! (Let’s do Express!)

Express was built by TJ Holowaychuk who got the inspiration from the Ruby on Rails framework Sinatra. The latest version of Express is 4.16.1. Express 4 became lighter by letting go of some of the modules that developers didn’t always use. So they could easily import them only when they needed. Makes sense right?

Express由TJ Holowaychuk构建,他从Ruby on Rails框架Sinatra获得了灵感。 Express的最新版本是4.16.1。 Express 4通过放开一些开发人员并不总是使用的模块而变得更轻便。 因此,他们可以仅在需要时轻松导入它们。 有道理吧?

To get started with Express, you need to install it and require it in your program.

要开始使用Express,您需要安装它并在程序中require它。

1) Create a folder called express-app, cd into it and hit npm init. This creates our package.json file.

1)创建一个名为express-app的文件夹,将其放入cd ,然后单击npm init 。 这将创建我们的package.json文件。

2) Still on the terminal or command line, hit npm install --save express. This will install express to the project. The double-dash save flag basically means we’re adding it to our package.json file.

2)仍然在终端或命令行上,单击npm install --save express 。 这将把Express安装到项目中。 双破折号save标志基本上意味着我们将其添加到package.json文件中。

3) On the root of our express-app folder, create a server.js file and copy this inside.

3)在我们express-app文件夹的根目录中,创建一个server.js文件并将其复制到其中。

const express = require('express'),app = express();app.get('/',(request,response)=>{response.send(‘Hello world’);
});//Binding the server to a port(3000)
app.listen(3000,()=>console.log(‘express server started at port 300’));

const express = require('express'),      app = express();app.get('/',(request,response)=>{  response.send(‘Hello world’);});//Binding the server to a port(3000)app.listen(3000,()=>console.log(‘express server started at port 300’));

const express = require('express'),app = express(); app.get('/',(request,response)=> {response.send('Hello world');}); //绑定服务器到端口(3000)app.listen(3000,()=> console.log('express服务器从端口300开始'));

4) Go back to the terminal, still in the same folder, and hit node server.js. Head to your browser and visit localhost.

4)返回终端,仍然在同一文件夹中,然后单击node server.js 。 前往浏览器并访问localhost 。

We’re requiring our Express module. If you were quite observant, you must have noticed we didn’t need the http module like we do in pure Node.js apps. That’s because Express requires it, so we don’t need to do that again.

我们需要我们的Express模块​​。 如果您很观察,您一定已经注意到我们不需要像纯Node.js应用程序中那样的http模块。 那是因为Express需要它,所以我们不需要再做一次。

When we require ('express’), what gets exported to us is a function, so we can basically call it directly and assign it to the app variable. At this point, nothing’s gonna work till we actually handle the request. This is called routing and it means giving the client what they are asking for.

当我们require ('express') ,导出到我们的是一个函数,因此我们基本上可以直接调用它并将其分配给app变量。 在这一点上,在我们真正处理请求之前,什么都不会起作用。 这被称为routing ,它意味着向客户提供他们想要的东西。

Express gives us some basic verbs to do HTTP operations (such as GET, POST, PUT and DELETE). In our example here, we do an app.get() method which handles get requests to the server. It takes two arguments: the path of the request and a callback to handle the request.

Express为我们提供了一些用于HTTP操作的基本动词(例如GET,POST,PUT和DELETE)。 在此处的示例中,我们执行一个app.get()方法来处理对服务器的获取请求。 它有两个参数:请求的path和处理请求的回调。

If you didn’t get this, I’ll explain more.

如果您不明白这一点,我将进一步说明。

A path is an address to a resource on a computer. A callback is a function passed to another function as an argument that is called when certain conditions happen.

路径是计算机上资源的地址。 回调是作为参数传递给另一个函数的函数,当某些情况发生时将调用该函数。

You might remember this:

您可能还记得:

$('p').click(function(){console.log('You clicked me')
});

Here, we add a callback to fire when p is clicked. See? It’s easy.

在这里,我们添加了一个单击p时触发的回调。 看到? 这很容易。

On the last line of server.js, we listen at port 3000 and console.log when we start the server.

server.js的最后一行,我们在启动服务器时侦听端口3000和console.log。

I bet you can’t write apps with that. Let’s get meaty.

我敢打赌你不能用它编写应用程序。 让我们变得多肉。

在Express中路由 (Routing in Express)

Routing means assigning functions to respond to users’ requests. Express routers are basically middleware (meaning they have access to the request and response objects and do some heavy lifting for us).

路由是指分配功能以响应用户的请求。 Express路由器基本上是中间件(这意味着它们可以访问requestresponse对象并为我们做一些繁重的工作)。

Routing in Express follows this basic format:

Express中的路由遵循以下基本格式:

app.VERB(‘path’, callback…);

Where VERB is any of the GET, POST, PUT, and DELETE verbs.

VERBGETPOSTPUTDELETE动词中的任何一个。

We can add as many callbacks as we desire. See an example here:

我们可以根据需要添加任意数量的回调。 在这里查看示例:

const express = require('express'),app = express();function sayHello(request,response,next){console.log(‘I must be called’);next();
}app.get('/', sayHello, (request, response)=>{response.send('sayHello');
});app.listen(3000,()=>console.log('Express server started at port 3000'));

Head to your terminal or command prompt and hit node server.js. You’ll see that the sayHello function fires before the response is sent to the browser.

转到终端或命令提示符,然后单击node server.js 。 您会看到在将响应发送到浏览器之前, sayHello函数将触发。

The sayHello function takes three arguments (request, response, and next).

sayHello函数采用三个参数( requestresponsenext )。

The next()function, when called, moves control to the next middleware or route.

调用next()函数时,会将控制权移至下一个中间件或路由。

请求和响应对象 (The request and response objects)

The request object contains information about the incoming request. Here are the most useful properties and methods:

request对象包含有关传入请求的信息。 以下是最有用的属性和方法:

The request.params variable stores an object of named GET request parameters. For example, clear your server.js file and paste this inside:

request.params变量存储一个名为GET请求参数的对象。 例如,清除您的server.js文件并将其粘贴到内部:

const express = require('express'),app = express();app.get('/:name/:age', (request, response)=>{response.send(request.params);
});app.listen(3000,()=>console.log(‘Express server started at port 3000’));

Run this with node server.js, then head to your browser and run: https://localhost:3000/john/5

使用node server.js运行它,然后转到浏览器并运行: https://localhost:3000/john/5

In the code above, we’re getting variables from the URL and sending them to the browser. The point is that the request.params is an object holding all those GET parameters. Notice the colon before the parameters. They differentiate route parameters from normal routes paths.

在上面的代码中,我们从URL获取变量并将其发送到浏览器。 关键是request.params是一个包含所有那些GET参数的对象。 注意参数前的冒号。 它们将路由参数与常规路由路径区分开。

The request.body property stores POST form parameters.

request.body属性存储POST表单参数。

The request.query property is used to extract the GET form data. Here’s an example of that:

request.query属性用于提取GET表单数据。 这是一个例子:

1) Create another folder called express-query, and then create two files: server.jsand form.html. Paste this into server.js :

1)创建另一个名为express-query文件夹,然后创建两个文件: server.jsform.html 。 将此粘贴到server.js

const express = require('express'),app = express();//route serves both the form page and processes form data
app.get('/', (request, response)=>{console.log(request.query);response.sendFile(__dirname +'/form.html');
});app.listen(3000,()=>console.log('Express server started at port 3000'));

2) Copy this to the form.html file:

2)将其复制到form.html文件:

<!--action specifies that form be handled on the same page-->
<form action='/' method='GET'><input type='text' name='name'/><input type='email' name='email'/><input type='submit'/>
</form>

Run the code with node server.js, hit localhost:3000, and fill and submit the form in your browser. After submitting the form, the data you filled out gets logged to the console.

使用node server.js运行代码,命中localhost:3000 ,然后在浏览器中填写并提交表单。 提交表单后,您填写的数据将记录到控制台。

request.headers hold key/pair values of the request received by the server. Servers and clients make use of headers to communicate their compatibility and constraints.

request.headers保留服务器接收到的请求的键/对值。 服务器和客户端利用标头来传达其兼容性和约束。

request.accepts([‘json’,’html’])holds an array of data formats and returns the format the browser prefers to collect data in. We’ll also see this when dealing with Ajax forms.

request.accepts(['json','html'])保存一系列数据格式,并返回浏览器更喜欢收集数据的格式。我们在处理Ajax表单时也会看到这一点。

request.url stores data about the URL of the request.

request.url 存储有关请求URL的数据。

request.ip: holds the IP (Internet protocol) address of the browser requesting for information.

request.ip:保存请求信息的浏览器的IP(Internet协议)地址。

The response object also ships with some convenient methods to get useful information about the outgoing request.

response对象还附带了一些便捷的方法来获取有关传出请求的有用信息。

response.send(message) sends its argument to the browser.

response.send(message) 将其参数发送到浏览器。

response.json() sends its argument as data to the browser in JSON format.

response.json() 将其参数作为数据以JSON格式发送到浏览器。

response.cookie(name,value,duration) provides an interface to set cookies on browsers. We’ll talk about cookies too.

response.cookie(name,value,duration) 提供了在浏览器上设置Cookie的界面。 我们也将谈论cookie。

response.redirect([redirect status], url) redirects the browser to the specified URL with the optional status.

response.redirect([redirect status], url)将浏览器重定向到具有可选状态的指定URL。

response.render(‘file’,{routeData: routedata}) renders a view to the browser and takes an object containing data the router might need. You’ll understand it better when we see views.

response.render('file',{routeData: routedata})将视图呈现给浏览器,并获取一个包含路由器可能需要的数据的对象。 当我们看到视图时,您会更好地理解它。

response.set(name,value) sets header values. But you don’t want to do that, as it gets in the way of the browser’s job.

response.set(name,value) 设置标题值。 但是您不想这样做,因为它会妨碍浏览器的工作。

response.status(status)sets the status of a particular response (404, 200, 401 and so forth).

response.status(status)设置特定响应的状态(404、200、401等)。

You don’t have to memorize all these. As we use them, you’ll subconsciously master them.

您不必记住所有这些。 当我们使用它们时,您将下意识地掌握它们。

快速路由器 (Express Router)

With Express Router, we can break our application into fragments that can have their own instances of express to work with. We can them bring them together in a very clean and modular way.

使用Express Router,我们可以将我们的应用程序分解为多个片段,这些片段可以具有自己的Express实例。 我们可以将它们以非常干净和模块化的方式整合在一起。

Let’s take for example. These four random URLs:

让我们举个例子。 这四个随机网址:

localhost:3000/users/john

本地主机:3000 / users / john

localhost:3000/users/mark

本地主机:3000 /用户/标记

localhost:3000/posts/newpost

本地主机:3000 / posts / newpost

localhost:3000/api

本地主机:3000 / api

Our normal approach of doing this with Express would be:

使用Express进行此操作的正常方法是:

const express = require('express'),app = express();//Different routes
app.get('/users/john',(request,response)=>{response.send(`John’s page`);
});app.get('/users/mark',(request,response)=>{response.send(`John’s page`);
});app.get('/posts/newpost',(request,response)=>{response.send(`This is a new post`);
});app.get('/api',(request,response)=>{response.send(‘Api endpoint’);
});app.listen(3000,()=>console.log(‘Server started at port 3000’));

There’s nothing wrong with this pattern at this point. But it has potential for errors. When our routes are basically just five, there isn’t much of a problem. But when things grow and lots of functionality is required, putting all that code in our server.js isn’t something we want to do.

此时,此模式没有任何问题。 但是它有潜在的错误。 当我们的路线基本上只有五条时,就没什么问题了。 但是,当事情发展并且需要大量功能时,将所有代码放入我们的server.js中并不是我们想要做的。

我们应该让路由器为我们做到这一点 (We should let Router do this for us)

Create a folder called react-router in the root of our project, create a file inside it, and call it basic_router.js. Copy this right in:

在我们项目的根目录中创建一个名为react-router的文件夹,在其中创建一个文件,并将其basic_router.js 。 将此权限复制到:

const express = require('express'),router = express.Router();//making use of normal routes
router.get('/john',(request,response)=>{response.send('Home of user');
});router.get('/mark',(request,response)=>{response.send('Home of user');
});//exporting thee router to other modules
module.exports = router;

We’re basically creating another instance of Express. This time, we’re calling the Router() function of Express. It’s possible to directly call express() as a function (as in our server.js) and call express.Router() also. This is because Express is exported as a function, and in JavaScript, functions are objects too.

我们基本上是在创建Express的另一个实例。 这次,我们调用Express的Router()函数。 可以直接调用express()作为一个函数(如在server.js ),也可以调用express.Router() 。 这是因为Express是作为函数导出的,在JavaScript中,函数也是对象。

We add routes to it as a normal Express app. But we don’t bind it to any port. The router object contains all the routes we’ve defined, so we export only that object so other parts of our program can make use of it too.

我们将路由添加为普通的Express应用。 但是我们不将其绑定到任何端口。 router对象包含我们定义的所有路由,因此我们仅导出该对象,因此程序的其他部分也可以使用它。

We create our main server.js, and add it as a middleware. Yes middlewares make work easier, remember?

我们创建主server.js ,并将其添加为中间件。 是的,中间件使工作更轻松,还记得吗?

const express = require('express'),app = express();//requiring the basic_router.js
app.use('/users',require('.react-router/basic_router'));//routes
app.get('/posts/newpost',(request,response)=>{response.send('new post');
});app.get('/api',(request,response)=>{response.send('API route');
});app.listen(3000,()=>console.log('Express server started at port 3000'));

Now run this. Navigate to localhost:3000/user/john and localhost:3000/user/mark. See? things are quite easy to group at this point.

现在运行这个。 导航到localhost:3000/user/johnlocalhost:3000/user/mark 。 看到? 在这一点上,事情很容易归类。

We can do this for every other route. Create another file for our APIs. We’ll call it api_route.js. Copy this right in:

我们可以针对其他所有路线执行此操作。 为我们的API创建另一个文件。 我们将其称为api_route.js 。 将此权限复制到:

const express = require('express'),router = express.Router();router.get('/',(request,response)=>{response.send('Home of user');
});//some other endpoints to submit data
module.exports = router;

Now, go back to our server.js and change the code to this:

现在,回到我们的server.js并将代码更改为此:

const express = require('express'),app = express();app.use('/users',require('./basic_router'));app.use('/api',require('./api_route'));app.get('/posts/newpost',(request,response)=>{response.send('new post');
});app.listen(3000,()=>console.log('Express server started at port 3000'));

This is quite enough information to build basic web app routes.

这些信息足以构建基本的Web应用程序路由。

模板引擎 (Template engines)

Most of the time, you aren’t definitive about the number of pages you want your website to have. This means you’d want to keep things flexible, reusable, and clean.

在大多数情况下,您对网站的网页数量不确定。 这意味着您希望保持事物的灵活性,可重用性和清洁性。

Imagine you have a footer that you might want to use on every page. Wouldn’t it be cool if you just put it in a file and embed it with a line of code on every page? Or how would like to lose the .html on your URL?

假设您有一个页脚,可能要在每个页面上使用。 如果只是将其放在文件中并在每一页上嵌入一行代码,那会不会很酷? 或者,如何丢失URL中的.html

These are just a few things template engines can do for us.

这些只是模板引擎可以为我们做的几件事。

There are a lot of template engines at the moment. But we’ll be using Handlebars to see how template works. Luckily enough, the same principles apply to pretty much all template engines — there are just syntax changes.

目前有很多模板引擎。 但是我们将使用把手来查看模板的工作方式。 幸运的是,几乎所有模板引擎都适用相同的原理-只是语法上的改变。

To make use of Handlebars, we install it.

为了利用车把,我们安装了它。

npm install --save express-handlebars

require it in your file and configure your app to use it like so:

在您的文件中require它,并配置您的应用程序以使其使用,如下所示:

const express = require('express'),hbs = require('express-handlebars').create({defaultLayout:'main.hbs'}),app = express();app.engine('hbs', hbs.engine);
app.set('view engine','hbs');

So let’s do a basic rendering with Handlebars:

因此,让我们使用Handlebars进行基本渲染:

  1. Create a folder called express-handlebars, create a views folder, and inside the views folder create another folder called layouts.

    创建一个名为express-handlebars的文件夹,创建一个views文件夹,然后在views文件夹内创建另一个名为layouts文件夹。

2) Create a server.js file and paste this inside:

2)创建一个server.js文件并将其粘贴到内部:

const express = require('express'),hbs = require('express-handlebars').create({defaultLayout:'main.hbs'}),app = express();//setting our app engine to handlebars
app.engine('hbs', hbs.engine);
app.set('view engine', 'hbs');
app.get('/',(request,response)=>{response.render('home',{title: 'Home'});
});app.get('/about',(request,response)=>{response.render(‘about’,{title: ‘About’});
});app.listen(3000,()=>console.log('Express server started at port 3000'));

3) Inside the layouts folder, create a file main.hbs. Paste this inside:

3)在layouts文件夹中,创建一个文件main.hbs 。 将此粘贴到里面:

<!-- The main.hbs file will act as a default template for every view on the site --><!DOCTYPE html>
<html>
<head>
<meta charset='UTF-8'><!-- The title variable will be replaced with the title of every page --><title>{{title}}</title>
</head><body>
<!-- Content of other pages will replace the body variable -->
{{{body}}}
</body>
</html>

4) Next, we’re going to create the separate views. Inside of the views folder, create two files — home.hbsand about.hbs. Paste the following inside home.hbs :

4)接下来,我们将创建单独的视图。 在views文件夹中,创建两个文件home.hbsabout.hbs 。 将以下内容粘贴到home.hbs

//home.hbs
<!-- This is the Home view and will render into the main.hbs layout --><div>Hello, I’m the Home page and you’re welcome
</div>

and in our about.hbs :

在我们的about.hbs

//about.hbs
<!-- This is the About view and will also render into the main.hbs layout --><div>Hello, I’m the about page, what do you want to know about
</div>

Do a node server.js in your terminal and hit http://localhost:3000 on your browser.

在终端中执行一个node server.js ,然后在浏览器中点击http://localhost:3000

What’s happening up here?

这是怎么回事

We first require express-handlebarsand create a defaultLayout, assigning it to main.hbs. This means that all our views will render into the main.hbs layout.

我们首先需要express-handlebars并创建一个defaultLayout ,将其分配给main.hbs 。 这意味着我们所有的视图都将呈现到main.hbs布局中。

Take a look at the server.js. Just a few things changed right? Let’s start with these two lines:

看一看server.js 。 只是几件事改变了吧? 让我们从这两行开始:

app.engine('hbs', hbs.engine);
app.set(‘view engine’,’hbs’);

The first line sets the app engine to hbs.engine and the second line sets the view engine property to handlebars. Quite straightforward right?

第一行将应用程序引擎设置为hbs.engine ,第二行将视图引擎属性设置为车把。 很直接吧?

The routes in our server.js are also a little different. Here’s the culprit:

我们的server.js中的路由也有所不同。 这是罪魁祸首:

response.render('home',{title: 'Home'});

While .send()sends plain text to the browser, render() looks for the first parameter in the views folder and renders it to the browser. Most of the time, we might want to pass dynamic content to the view too. We give the render method an object as the second parameter. The object contains keys and values of data to be passed inside the view.

.send()将纯文本发送到浏览器时, render()views文件夹中查找第一个参数,并将其呈现到浏览器。 大多数时候,我们可能也想将动态内容传递给视图。 我们给render方法一个对象作为第二个参数。 该对象包含要在视图内部传递的数据的键和值。

Take this line in our main.hbs file in our layout folder.

在布局文件夹中的main.hbs文件中使用此行。

//main.hbs
<title>{{title}}</title>

The {{title}} is replaced with whatever is passed with the view. In our case, the {title: 'Home'}. We can pass as many values as we want to the view. Just add it as a property of the object.

{{title}}被视图传递的内容所代替。 在我们的例子中, {title: 'Home'} 。 我们可以向视图传递任意数量的值。 只需将其添加为对象的属性即可。

When we do a response.render(), Express knows where to get the files we ask for. Let’s look into the about.hbs.

当我们执行response.render() ,Express知道从哪里获取我们要求的文件。 让我们看一下about.hbs

<!-- This is the About view and will render into the main.handlebars layout -->
<div>Hello, I’m the about page, what do you want to know about
</div>

The content of this file replaces the body variable in our layout.handlebars:

该文件的内容替换了我们layout.handlebars的body变量:

{{{body}}}

If you’re asking why we’re using two braces for {{title}} and three for the {{{body}}} , you’re on the right track.

如果您要问为什么我们在{{title}}中使用两个大括号,而在{{{body}}}中使用三个大括号,那么您的方向正确。

When we use two braces, we spit out everything, even the HTML tags (unescaped). Here’s what I mean.

当我们使用两个大括号时,我们吐出了所有内容,甚至包括HTML标记(未转义)。 这就是我的意思。

If the content we want to send to the browser is <b>Hello world</b>, with two braces, Express will render it as <b&gt;Hello world</b>. If we make use of three braces, Express will understand that we want a bold text and render it as Hello world (bolded).

如果我们要发送给浏览器的内容是<b>Hello wor </ b>,带有两个大括号,Express会将其ender it as <b&g t; Hello world </ b>。 如果我们使用三个大括号,Express将会理解我们想要一个纯文本并将其呈现为Hello world(粗体)。

This is basically how template engines work in Express. Handlebars provides a one page documentation. I consider it a good place to start.

基本上,这就是Express中模板引擎的工作方式。 车把提供一页文档。 我认为这是一个不错的起点。

在Express中呈现静态内容 (Rendering static content in express)

Have you ever thought of where we’ll store our CSS, JavaScript files, and images? Well, Express provides a middleware to make the server know where to find static content.

您是否想到过将CSS,JavaScript文件和图像存储在何处? 好吧,Express提供了一个中间件,使服务器知道在哪里可以找到静态内容。

Here’s how to make use of it:

使用方法如下:

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

Put this at the top of your server.js, right after the require statements. __dirname holds the path where the program is being run from.

将其放在require。语句之后的server.js顶部。 __dirname包含从中运行程序的路径。

If you didn’t get that, try this.

如果没有得到,请尝试此操作。

Delete everything on your server.js, and put this inside:

删除server.js上的所有内容,并将其放入其中:

console.log(__dirname);

console.log(__dirname);

Head to your command line, and run node server.js. It shows you the path to the file node that is running.

转到命令行,然后运行node server.js 。 它向您显示正在运行的文件节点的路径。

Where we store our static content is up to us. We might want to name it assetsor whatever, but you have to make sure you append it to the dirname like so:

我们存储静态内容的位置取决于我们。 我们可能想将其命名为assets或其他名称,但是您必须确保将其附加到dirname如下所示:

express.static(__dirname + ‘static_folder_name’).

快速中间件 (Express Middleware)

Middleware are functions that encapsulate functionality. They perform operations on HTTP requests and give us a high-level interface to customize them. Most middleware take three arguments: request, response objects, and a next function. In error handling middleware, there’s an additional parameter: the err object, which can tell us about the error and let us pass it to other middleware.

中间件是封装功能的功能。 它们对HTTP请求执行操作,并为我们提供了高级界面以对其进行自定义。 大多数中间件采用三个参数: requestresponse对象和next函数。 在错误处理中间件中,还有一个附加参数: err对象,它可以告诉我们错误并将其传递给其他中间件。

We add middleware to our server by using app.use(name_of_middleware). It’s also important to note that middleware are used in the same order they were added. I’ll show you an example later if you don’t understand.

我们使用app.use(name_of_middleware)将中间件添加到服务器中。 同样重要的是要注意,中间件的使用顺序与添加时相同。 如果您不了解,我稍后将为您提供示例。

With this definition, we can also see route functions like app.get(), app.post() and so on, as middleware, except that they are applied to particular HTTP verb requests. You might also find it interesting to know that there’s an app.all()route that is applied to all HTTP requests not considering if they were a GET, POST, or other request.

通过此定义,我们还可以将路由函数app.get()app.post()等视为中间件,只是将它们应用于特定的HTTP动词请求。 您可能还会发现有趣的是,有一条app.all()路由应用于所有HTTP请求,而不考虑它们是GET,POST还是其他请求。

//This middleware will be called for every request. GET or POST
app.all((request,response)=>{console.log('Hello world');
})

Route handlers take two parameters, the path to match and the middleware to execute.

路由处理程序采用两个参数,即匹配路径和要执行的中间件。

app.get('/',(request,,response)=>{response.send(‘Hello world’);
});

If the path is left out, the middleware applies to every GET request.

如果路径被忽略,则中间件将应用于每个GET请求。

//Every GET request will call this middleware
app.get((request,response)=>{response.send(‘Hello world’);
});

In our example above, once we send a GETrequest, our server responds to the browser by sending a ‘Hello world’ message and then terminates until there’s another request.

在上面的示例中,一旦我们发送GET请求,我们的服务器就会通过发送'Hello world'消息来响应浏览器,然后终止直到有另一个请求。

But we might want more than one middleware to be called. There’s a way to do this. Remember our next function? We could make use of it to push control to another middleware.

但是我们可能希望调用多个中间件。 有一种方法可以做到这一点。 还记得我们的next功能吗? 我们可以利用它来将控制推到另一个中间件。

Let’s see how this works. Copy and paste this code into our server.js:

让我们看看它是如何工作的。 将此代码复制并粘贴到我们的server.js:

const express = require('express'),app = express();//setting the port
app.set(‘port’, process.env.PORT || 3000);//first middleware
app.use((request,respone,next)=>{console.log(`processing for data for ${request.url}`);next();
});//second middleware
app.use((request,response,next)=>{console.log(`The response.send will terminate the request`);
response.send(`Hello world`);
});//third middleware
app.use((request,respone,next)=>{console.log(`I’ll never get called`);
});app.listen(3000,()=>console.log('Express server started at port 3000'));

From the terminal, hit node server.js and take a look at the terminal. Head to your browser and open up localhost:3000. Look at your console again, and you’ll see something similar.

在终端上,单击node server.js并查看终端。 转到浏览器并打开localhost:3000 。 再次查看您的控制台,您会看到类似的内容。

Express server started at port 3000
processing for data for /
The response.send will terminate the request

Our first middleware executes every time a request is received. It writes something to the console and calls the next()function. Calling the next() function tells Express to not terminate the request object but sends control to the next middleware. Anytime we write a middleware without calling the next function, Express terminates the requestobject.

每当收到请求时,我们的第一个中间件就会执行。 它将一些内容写入控制台并调用next()函数。 调用next()函数告诉Express不要终止request对象,而是将控制权发送给下一个中间件。 每当我们编写中间件而没有调用next函数时,Express都会终止request对象。

In the second middleware, we pass the next() function as an argument but we never call it. This terminates the request object and the third middleware never gets called. Note that if we never sent anything to the browser in the second middleware, the client will eventually timeout.

在第二个中间件中,我们将next()函数作为参数传递,但是我们从不调用它。 这将终止request对象,并且永远不会调用第三个中间件。 请注意,如果我们从不向第二个中间件中的浏览器发送任何内容,则客户端最终将超时。

Here are some useful middleware in Express.js:

这是Express.js中一些有用的中间件:

  • Morgan — log each request

    Morgan-记录每个请求

  • CORS — enables Cross Origin Request Sharing

    CORS —启用跨源请求共享

  • body-parser — a middleware to parse the request.body in Express apps

    body-parser —在Express应用程序中解析request.body的中间件

  • Multer — Node.js middleware for handling multipart/form-data

    Multer —用于处理multipart/form-data Node.js中间件

  • session — simple session middleware for Express.js

    会话 — Express.js的简单会话中间件

  • errorhandler — development-only error handler middleware

    errorhandler —仅开发错误处理程序中间件

  • serve-favicon — favicon serving middleware

    serve-favicon —提供服务的favicon中间件

  • csurf — Node.js CSRF protection middleware

    csurf — Node.js CSRF保护中间件

  • Passport — Simple, unobtrusive authentication

    护照 -简单,简单的身份验证

  • Merror — A RESTful-friendly Express Middleware for HTTP error handling and error responses

    Merror — RESTful友好的Express中间件,用于HTTP错误处理和错误响应

  • Expressa — express middleware for easily making REST APIs

    Expressa —用于轻松制作REST API的快速中间件

在Express中处理表单数据 (Handling form data in Express)

The web’s main function is communication. Express provides us with tools to understand what clients request and how to respond properly.

网络的主要功能是通信。 Express为我们提供了了解客户要求以及如何正确响应的工具。

Express basically has two places to store client data. The request.querystring(for GET request) and the request.body (for POST requests). On the client side, it’s ideal to use the POST method for form submission because most browsers place limits on the length of the querystring and additional data is lost. If you don’t know what a query string is, it’s the part after your URL that contains data and does not fit properly into your routing path system. In case you don’t quite understand what a query string is, here’s an example:

Express基本上有两个地方可以存储客户端数据。 request.querystring(用于GET请求)request.body(用于POST请求) 。 在客户端,使用POST方法进行表单提交是理想的,因为大多数浏览器都会限制querystring的长度,并且会丢失其他数据。 如果您不知道查询字符串是什么,则它是URL后面的部分,其中包含数据,并且不适合您的路由路径系统。 如果您不太了解查询字符串是什么,请看以下示例:

facebook.com/users?name=Victor&age=100&occupation=whatever

From the point where the question mark begins is called the query string. It passes data to the server but exposes it in the URL.

从问号开始的地方称为查询字符串。 它将数据传递到服务器,但在URL中公开。

It’s also good practice to keep the query string as clean as possible. Sending large data with GET requests makes the query string messy.

保持查询字符串尽可能整洁也是一个好习惯。 使用GET请求发送大数据会使查询字符串混乱。

Let’s see a demo. We’ll take some data from our client via GET and send it back to them.

让我们看一个演示。 我们将通过GET从客户那里获取一些数据,并将其发送回给他们。

Create a folder, call it form-data , and create two files inside: server.js and form.html. Paste this into the server.js file and form.html files respectively:

创建一个文件夹,将其称为form-data ,并在其中创建两个文件: server.jsform.html 。 分别将其粘贴到server.js文件和form.html文件中:

//server.js fileconst express = require('express'),app = express();//setting the port
app.set('port', process.env.PORT || 3000);//
app.get('/',(request,response)=>{response.sendFile(__dirname +'/form.html');
});app.get('/process',(request,response)=>{console.log(request.query);response.send(`${request.query.name} said ${request.query.message}`);
});app.listen(3000,()=>{console.log('Express server started at port 3000');
});
//form.html<!DOCTYPE html>
<html><head><meta charset='UTF-8'><title>Form page</title><style>*{margin:0;padding:0;box-sizing: border-box;font-size: 20px;}input{margin:20px;padding:10px;}input[type=”text”],textarea {width:200px;margin:20px;padding:5px;height:30px;display: block;}textarea{resize:none;height:60px;}</style></head>
<body><form action='/process' method='GET'><input type='text' name='name' placeholder='name'/><textarea name='message' placeholder='message'></textarea><input type='submit'/></form>
</body>
</html>

Run node server.js, head to localhost:3000, fill the form and submit it.

运行node server.js ,转至localhost:3000 ,填写表格并提交。

Here’s what the result would look like.

结果如下所示。

In our server.js file here, we have to two GET routes. One for localhost:3000 and localhost:3000/process.

在这里的server.js文件中,我们必须有两个GET路由。 一个用于localhost:3000localhost:3000/process

app.get(‘/’,(request,response)=>{response.sendFile(__dirname + ‘/form.html’);
});

And

app.get(‘/process’,(request,response)=>{response.send(`${request.query.name} said ${request.query.message}`);
});

Head to your your console. You’ll see an object. This proves that our request.query is an object that contains all queries and their values.

进入您的控制台。 您会看到一个对象。 这证明我们的request.query是一个包含所有查询及其值的对象。

{name: 'victor',message: 'Hello world'
}

If you take a look at our form in the form.htmlpage, you’ll notice our form has action and methodattributes. The actionattribute specifies the page or route that should handle the form’s data (‘process’ in this case). When the form gets submitted, it sends a GET request to the processroute with the content of our form as querystringdata.

如果您在form.html页面上查看我们的表单,您会发现我们的表单具有actionmethod属性。 action属性指定应处理表单数据的页面或路由(在这种情况下为“过程”)。 提交表单后,它将GET请求发送到process路由,表单的内容作为querystring数据。

Our server.js file also handles the request for the process path and sends data passed from our form.html to the browser and console.

我们的server.js文件还处理对流程路径的请求,并将从form.html传递的数据发送到浏览器和控制台。

Let’s see how we would handle this with the POST method. It’s time to clear our server.jsfile. Copy and paste this code into server.js:

让我们看看如何使用POST方法处理此问题。 现在该清除我们的server.js文件了。 将此代码复制并粘贴到server.js

//server.jsconst express = require('express'),app = express(),//You must require the body-parser middleware to access request.body in express
bodyParser = require('body-parser');//configuring bodyparser
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));//setting our port
app.set('port', process.env.PORT || 3000);//Get route for localhost:3000
app.get('/',(request,response)=>{response.sendFile(__dirname +'/form.html');
});//POST route for form handling
app.post('/',(request,response)=>{console.log(request.body);  response.send(`${request.body.name} said ${request.body.message}`);
});app.listen(3000,()=>{console.log('Express server started at port 3000');
});

If you look closely, the first different thing we’re doing is requiring and using body-parser. Body-parser is a middleware that makes POST data available in our request.body. Bear in mind that the request.body won’t work without the body-parser middleware.

如果仔细观察,我们要做的第一件事就是需要并使用body-parser 。 Body-parser是一个中间件,可在我们的request.body提供POST数据。 请记住,没有body-parser中间件, request.body将无法工作。

You might also notice we have both GET and POST route handlers. The GET middleware shows the form and the POST middleware processes it. It’s possible for both of them to use one route path because they have different methods.

您可能还会注意到我们同时具有GET和POST路由处理程序。 GET中间件显示表单,而POST中间件对其进行处理。 由于它们使用的方法不同,因此它们都可能使用一条路由路径。

We couldn’t do this for our first example because our form method was GET. Obviously, you can’t have two GET requests for the same route and have both of them send data to the browser. That’s why our first example processed the form on the /process path.

对于第一个示例,我们无法执行此操作,因为我们的表单方法是GET。 显然,对于相同的路由,您不能有两个GET请求,并且它们都必须将数据发送到浏览器。 这就是为什么我们的第一个示例在/process路径上处理表单。

处理AJAX表单 (Handling AJAX forms)

Handling Ajax forms with Express is quite straightforward. Express provides us with a request.xhrproperty to tell us if a request is sent via AJAX. We can couple that with the request.accepts()method we talked about earlier. It helps us determine what format the browser wants the data in. If the client will like JSON, well, we’ll just give it JSON.

使用Express处理Ajax表单非常简单。 Express为我们提供了request.xhr属性,以告知我们是否通过AJAX发送了请求。 我们可以将其与前面讨论的request.accepts()方法结合使用。 它可以帮助我们确定浏览器需要哪种格式的数据。如果客户端喜欢JSON,那么我们就给它JSON。

Let’s modify our form.html to use AJAX and our server.js to accept AJAX and send JSON.

让我们修改form.html以使用AJAX,并修改server.js接受AJAX并发送JSON。

<!DOCTYPE html>
<html><head><meta charset='UTF-8'><title>Form page</title><script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.js'></script><style>*{margin:0;padding:0;box-sizing: border-box;font-size: 20px;}input{margin:20px;padding:10px;}input[type=”text”],textarea {width:200px;margin:20px;padding:5px;height:30px;display: block;}textarea{resize:none;height:60px;}</style></head>
<body><div></div><form action='/' method='POST'><input type='text' name='name' placeholder='name'/><textarea name='message' placeholder='message'></textarea><input type='submit'/></form><script>$('form').on('submit',makeRequest);function makeRequest(e){e.preventDefault();$.ajax({url:'/',type : 'POST',success: function(data){if(data.message){$('div').html(data.message);} else {$('div').html('Sorry, an error occured');}},error: function(){$('div').html('Sorry, an error occurred');}});}</script></body>
</html>
//server.jsconst express = require('express'),app = express(),bodyParser = require('body-parser');//configuring the body-parser middleware
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));//setting our app port
app.set('port', process.env.PORT || 3000);//Route for  get requests.
app.get('/',(request,response)=>{response.sendFile(__dirname +'/form.html');
});//Route to handle POST form requests.
app.post('/',(request,response)=>{
//we check if the request is an AJAX one and if accepts JSONif(request.xhr || request.accepts('json, html')==='json'){response.send({message:'Just wanted to tell you. It worked'});} else {//Do something else by reloading the page.}
});app.listen(3000,()=>{console.log('Express server started at port 3000');
});

这是这样的 (Here’s how this works)

Not much changes here — we just added a way to vet if the request was made with AJAX.

这里没有太多更改-如果请求是使用AJAX进行的,我们只是添加了一种方法来审核。

So here’s what we’re doing. We made the request an AJAX one with the POST method. We linked to jQuery CDN. In the script tag, we attach an event handler for the submit event. When we do this, we prevent the default behavior of reloading the page.

这就是我们正在做的。 我们使用POST方法将请求设为AJAX请求。 我们链接到jQuery CDN。 在脚本标签中,我们为Submit事件附加了一个事件处理程序。 当我们这样做时,我们防止了重新加载页面的默认行为。

We then use the jQuery $.ajax() method to make an AJAX request. The server responds with an object with a messageproperty, which we then append to the empty div.

然后,我们使用jQuery $.ajax()方法发出AJAX请求。 服务器以带有message属性的对象作为响应,然后将其附加到空div上。

If you aren’t familiar with AJAX, I once wrote some articles on AJAX. Check them out: A gentle introduction to AJAX and Easier asynchronous requests with jQuery.

如果您不熟悉AJAX,我曾经写过一些有关AJAX的文章。 查看它们: AJAX和jQuery的异步请求的轻松 介绍 。

Node.js应用程序中的数据库 (Databases in Node.js apps)

MongoDB and CouchDB are some database systems that are suitable for Node.js applications. This doesn’t completely rule out the possibility of using other databases. We’ll look at MongoDB, but you can choose any one you like.

MongoDB和CouchDB是一些适用于Node.js应用程序的数据库系统。 这并不完全排除使用其他数据库的可能性。 我们将研究MongoDB,但是您可以选择任何一个。

Documents replace rows in a relational database like MySQL. In MongoDB and other document-based databases, data is stored and retrieved in an object format. This means we can have deeply nested structures.

文档替换了关系数据库(如MySQL)中的行。 在MongoDB和其他基于文档的数据库中,数据以对象格式存储和检索。 这意味着我们可以拥有深层嵌套的结构。

If you consider objects in JavaScript, there’s no way to validate that the value of an object property is a particular type. Here’s what I mean:

如果考虑使用JavaScript中的对象,则无法验证对象属性的值是特定类型。 这就是我的意思:

const obj = { text : 1234}

const obj = { text : 1234}

There’s no way to make sure the value of textis a string.

无法确保text的值是字符串。

Fortunately, there’s Mongoose. Mongoose allows you define schemas that strongly validate data and ensure they match objects or documents in a MongoDB. Mongoose is an Object Document Mapper (ODM).

幸运的是,有猫鼬。 Mongoose允许您定义用于强烈验证数据并确保它们与MongoDB中的对象或文档匹配的架构。 猫鼬是一个对象文档映射器(ODM)。

An introduction to Mongoose is a nice place to start exploring and working with Mongoose.

猫鼬入门是开始探索和使用猫鼬的好地方。

Express中的会话和Cookie (Sessions and Cookies in Express)

HTTP is stateless. Meaning any request or response sent by the browser or server respectively maintains no information (state) about the previous or future requests and responses. Every single request has all it takes to evoke a new server response.

HTTP是无状态的。 意味着浏览器或服务器发送的任何请求或响应分别不保留有关先前或将来的请求和响应的信息(状态)。 每个单个请求都具有引发新服务器响应所需要的一切。

But there has to be a way for servers to remember clients as they browse through the site so they don’t have to enter passwords on every page.

但是服务器必须有一种方法来记住客户端,因为客户端在浏览网站时不必在每个页面上都输入密码。

The web has been innovative enough to make use of cookies and sessions. Cookies are basically small files stored on the client’s machine. When clients send requests, the server uses it to identify them. More like a passport, the server then knows it’s them and applies all their preferences.

网络已经足够创新,可以使用cookie和会话。 Cookies基本上是存储在客户端计算机上的小文件。 客户端发送请求时,服务器使用它来识别请求。 服务器更像护照,然后会知道是他们并应用他们的所有首选项。

So the idea would be to store files on the client’s machine. While this is not a bad idea, we want to make sure we don’t abuse the user’s storage by storing huge amounts of data. On the other side of things, we understand that if we want to make things harder to guess and more secure, we make it longer and more complex. How can we achieve these two concurrently?

因此,想法是将文件存储在客户端计算机上。 虽然这不是一个坏主意,但我们要确保我们不会通过存储大量数据来滥用用户的存储。 在另一方面,我们了解到,如果我们想使事情变得更难以猜测和更加安全,那么我们将使其变得更长,更复杂。 我们如何同时实现这两个目标?

People came up with sessions. So the idea of sessions is that instead of storing all the information on the client’s cookie, the server stores an identifier in the cookie (a small string). When the client sends requests, the server takes that unique string and matches it to the user’s data on the server. This way, we get to store any amount of data and still remember users.

人们提出了会议。 因此,会话的想法是,服务器将标识符存储在cookie中(一个小字符串),而不是将所有信息存储在客户端的cookie中。 当客户端发送请求时,服务器将使用该唯一字符串并将其与服务器上用户的数据进行匹配。 这样,我们可以存储任何数量的数据,并且仍然记住用户。

To make use of cookies in Express, we need to require the cookie-parser middleware. Remember our middleware?

要在Express中使用cookie,我们需要cookie-parser中间件。 还记得我们的中间件吗?

I’m not in the best position to explain this in depth. But someone did it better here: Express sessions.

我无法最好地深入解释这一点。 但是有人在这里做得更好: 快速会议 。

Express应用程序中的安全性 (Security in Express apps)

The web is not secured by default. Packets are the way data is sent over the web. These packets are unencrypted by default. When we think about web security, the first place to start is to secure those packets.

默认情况下,网络不受保护。 数据包是通过网络发送数据的方式。 这些数据包默认情况下是未加密的。 考虑网络安全时,首先要确保这些数据包的安全。

HTTPS: That’s no new word! Like you might have guessed, the difference between HTTP and HTTPS is the S (Security). HTTPS encrypts packets traveling through the web so people don’t do malicious things with it.

HTTPS :这不是一个新词! 就像您可能已经猜到的那样,HTTP和HTTPS之间的区别是S(安全性)。 HTTPS会对通过网络传输的数据包进行加密,因此人们不会对其进行恶意处理。

那么我该如何获取HTTPS? (So how do I go about getting HTTPS?)

Chill, let’s take it slow. To get HTTPS, you need to approach a Certificate Authority (CA). HTTPS is based on the server having a public key certificate, sometimes called an SSL. CAs assign certificates to qualified servers. You have to also understand that CAs make root certificates that get installed when you install your browser. So browsers can easily communicate with servers with certificates too.

冷静,让我们慢慢来。 要获取HTTPS,您需要联系证书颁发机构(CA)。 HTTPS基于具有公共密钥证书(有时称为SSL)的服务器。 CA将证书分配给合格的服务器。 您还必须了解,CA会生成在安装浏览器时安装的根证书。 因此,浏览器也可以轻松地通过证书与服务器通信。

Good news: Anybody can make their own certificates.

好消息 :任何人都可以制作自己的证书。

Bad news: The browsers can’t recognize those certificates because they weren’t installed as root certificates.

坏消息 :浏览器无法识别这些证书,因为它们不是作为根证书安装的。

Impossible: You can’t configure all the browsers in the world during installation to recognize your certificate.

不可能 :您无法在安装过程中配置世界上所有的浏览器来识别您的证书。

I can tell what you’re thinking now. You’re thinking that you can create your own certificate for testing and development and get one in production. Well, that’s smart and possible.

我可以告诉你现在在想什么。 您在考虑可以创建自己的用于测试和开发的证书并在生产中获得证书。 好吧,这很聪明而且可能。

The browser will give you warnings, but you are aware of the problem so it won’t be much of an issue. Here’s a post that walks you through creating your own certificate.

浏览器会向您发出警告,但是您已经知道了问题,因此不会有太大的问题。 这里有一个职位是引导您完成创建您自己的证书。

How to Set Up HTTPS Locally Without Getting Annoying Browser Privacy ErrorsSetting up HTTPS locally can be tricky business. Even if you do manage to wrestle self-signed certificates into…deliciousbrains.com

如何在不引起浏览器隐私错误的情况下 在本地设置HTTPS可能是一件棘手的事情。 即使您确实设法将自签名证书摔入…… Deliciousbrains.com

Enough talking. Let’s assume you now have the SSL certificate. Here’s how to make it work with your Express app.

聊够了。 假设您现在拥有SSL证书。 这是使其与Express应用程序一起使用的方法。

在您的Node应用程序中启用HTTPS (Enabling HTTPS in your Node app)

We need to make use of the https module for HTTPS. After obtaining our credentials from a Certificate Authority, we’ll include it as an argument to the createServer() method.

我们需要对HTTPS使用https模块。 从证书颁发机构获得我们的凭据后,我们会将其作为参数添加到createServer() 方法。

//server.jsconst express = require('express'),https = require('https'),http = require('http'),fs = require('fs'),app = express();//credentials obtained from a Certificate Authority
var options = {key: fs.readFileSync('/path/to/key.pem'),cert: fs.readFileSync('/path/to/cert.pem')
};//Binding the app on different ports so the app can be assessed bt HTTP and HTTPS
http.createServer(app).listen(80);
https.createServer(options, app).listen(443);

Notice we’re requiring httpand https. This is because we want to respond to both. In our program, we’re making use of the fs module (file-system).

注意,我们需要httphttps. 这是因为我们想对两者做出回应。 在我们的程序中,我们正在使用fs模块(文件系统)。

We basically provide the path to where our SSL key and certificate is stored. A module or something. Observe that we’re making use of the readFileSync method instead of the readFile. If you understand Node.js architecture, you’ll infer that we want to read the file synchronously before running any other lines of code.

我们基本上提供了SSL密钥和证书的存储路径。 模块或其他东西。 观察到我们正在使用readFileSync 方法,而不是readFile 。 如果您了解Node.js架构,则可以推断我们希望在运行任何其他代码行之前同步读取文件。

Running this code asynchronously might lead to situations where aspects of our code that require the content of the file don’t get them on time.

异步运行此代码可能会导致以下情况:需要文件内容的代码某些方面无法按时得到。

The last two lines bind the HTTP and HTTPS to two different ports and take different arguments. Why are we doing this?

最后两行将HTTP和HTTPS绑定到两个不同的端口,并采用不同的参数。 我们为什么这样做呢?

At most times, we want our server to still listen to requests with HTTP and maybe redirect them to HTTPS.

在大多数情况下,我们希望我们的服务器仍然使用HTTP侦听请求,甚至可以将其重定向到HTTPS。

Note: the default port for HTTPS is 443.

注意 :HTTPS的默认端口是443。

To do this basic redirect, we’ll install and require a module express-force-ssl at the top of our program like so:

要执行此基本重定向,我们将在程序顶部安装并需要一个模块express-force-ssl ,如下所示:

npm install express-force-ssl

And configure like so:

并像这样配置:

const express_force_ssl = require('express-force-ssl');
app.use(express_force_ssl);

Now, our server can take care of both HTTP and HTTPS requests effectively.

现在,我们的服务器可以有效地处理HTTP和HTTPS请求。

跨站请求伪造(CSRF) (Cross-Site Request Forgery (CSRF))

This is the other big thing you’d want to protect yourself from. It happens when requests come to your server but not directly from your user. For example, you have an active session on Facebook.com and you have another tab open. Malicious scripts can run on the other site and make requests to Facebook’s server.

这是您要保护自己免受伤害的另一件大事。 当请求到达您的服务器而不是直接来自用户时,就会发生这种情况。 例如,您在Facebook.com上有一个活动会话,并且打开了另一个选项卡。 恶意脚本可以在其他站点上运行,并向Facebook服务器发出请求。

A way to handle this is to ensure that requests come only from your website. That’s quite easy. We assign an ID to users and attach it to forms, so when they submit, we can match up the ID and deny access if it doesn’t match.

处理此问题的一种方法是确保请求仅来自您的网站。 那很容易。 我们为用户分配一个ID并将其附加到表单,因此当他们提交表单时,我们可以匹配该ID并在不匹配时拒绝访问。

Luckily, there’s a middleware that handles this — csurfmiddleware. Here’s how to use it:

幸运的是,有一个可以处理此csurf中间件csurf中间件。 使用方法如下:

npm install csurf

To use it in our program:

要在我们的程序中使用它:

const express = require('express'),body_parser = require('body-parser'),hbs = require('express-handlebars').create({defaultLayout: 'main',extname:'hbs'});session = require('express-session'),csurf = require('csurf'),app = express();//setting the app port
app.set('port', process.env.PORT || 3000);//configuring the app for handlebars
app.engine('hbs', hbs.engine);
app.set('view engine', 'hbs');//setting up a session csrf
app.use(session({name: 'My session csrf',secret: 'My super session secret',cookie: {maxAge: null,httpOnly: true,secure: true}}));app.use(csurf());//configuring the body parser middleware
app.use(body_parser.urlencoded());//Route to login
app.get('/login', (request,response)=>{console.log(request.csrfToken());response.render('login',{csrfToken : request.csrfToken(),title: 'Login'});
});app.listen(3000,()=>console.log('Express app started at port 3000'));
<b>Here's the generated csrf token</b> ({{csrfToken}})<br><br><form method='POST' action='/process'><!-- We pass the _csrf token as a hidden input --><input type='hidden' name='_csrf' csurf={{csrfToken}}/><input type='text' name='name'/><input type='submit'/>
</form>

Run node server.js , head to your browser localhost:3000, fill the form and submit. Also check in your command line and see the token logged.

运行node server.js ,转到浏览器localhost:3000 ,填写表格并提交。 另外,请在命令行中检查并查看已记录的令牌。

What we’re doing is generating and passing the csrfToken to our login view.

我们正在做的是生成csrfToken并将其csrfToken到我们的登录视图。

Note: The csurf module requires express-session module to work. We configure our session CSRF and pass it to the view via the response.render() method.

注意: csurf模块需要express-session模块才能工作。 我们配置会话CSRF并通过response.render()方法将其传递给视图。

Our view can now append it to the form or any other sensitive request.

现在,我们的视图可以将其追加到表单或任何其他敏感请求。

So what happens when the browser doesn’t get the CSRF token from the browser forms? It spits an error. Make sure you have an error handling route in your Express application, or else your application might misbehave.

那么当浏览器没有从浏览器表单中获取CSRF令牌时会发生什么呢? 它吐出一个错误。 确保Express应用程序中有错误处理路线,否则您的应用程序可能行为不当。

认证方式 (Authentication)

One step to reduce authentication problems is to let people sign up and sign in with third-party apps (Facebook, Twitter, Google,+ and so on). A whole lot of people have these accounts, and you can also have access to some of their data like emails and usernames. Modules like passport.js provide a very elegant interface to handle such authentications.

减少身份验证问题的一个步骤是让人们注册并使用第三方应用程序(Facebook,Twitter,Google等)登录。 很多人都有这些帐户,您也可以访问他们的某些数据,例如电子邮件和用户名。 诸如passport.js模块提供了一个非常优雅的界面来处理这种身份验证。

Here’s the official passport.js documentation. I think it’s a nice place to start.

这是官方的password.js文档 。 我认为这是一个不错的起点。

Another step to reduce authentication problems is to always encrypt all passwords and decrypt them back when showing them to the users.

减少身份验证问题的另一步是,始终加密所有密码,并在向用户显示密码时将其解密。

One more thing. I see this on a lot of websites. They set crazy criteria for users’ password on the site. I understand that they’re trying to make passwords more secure, but think about it. Whose job is it? The developer or the user?

还有一件事。 我在很多网站上都看到了这一点。 他们为网站上的用户密码设置了疯狂的条件。 我了解他们正在尝试使密码更安全,但请考虑一下。 这是谁的工作? 开发人员还是用户?

The user should be least bothered about security issues. When criteria like these are set on passwords, users have no other option than to use passwords they’ll never remember. I know the web is getting better and we’ll figure out a way to make authentication better.

用户应该至少对安全问题感到困扰。 当在密码上设置此类条件时,用户别无选择,只能使用他们永远不会记住的密码。 我知道网络越来越好,我们将找出一种使身份验证更好的方法。

Till then I think we can end this here.

到那时,我认为我们可以在这里结束。

This is a lot of information. But you need more than this to build scalable web applications. Here are some insightful books for learning more about Express.

这是很多信息。 但是,您不仅仅需要构建可伸缩的Web应用程序。 这是一些有见地的书,可用于进一步了解Express。

If this was useful, you should follow me on Twitter for more useful stuff.

如果这有用,您应该在Twitter上关注我,以获取更多有用的信息。

  1. Express in action by Evan Hahn.

    快速行动由埃文·哈恩 。

  2. Getting MEAN with Express, Mongo, Angular and Node by Simon Holmes.

    Simon Holmes通过Express,Mongo,Angular和Node获得MEAN 。

翻译自: https://www.freecodecamp.org/news/getting-off-the-ground-with-expressjs-89ada7ef4e59/

express-cli入门

express-cli入门_使用Express.js入门相关推荐

  1. vue设置cookie的domain无效_【Vue.js入门到实战教程】16Tailwind 与 Bootstrap 的区别和使用入门...

    来源 | https://xueyuanjun.com/post/22065我们知道,从 Laravel 8 开始,自带前端脚手架代码默认兼容 Tailwind CSS 框架,取代了之前的 Boots ...

  2. js模板字符串自定义类名_【Vue.js 入门到实战教程】07Vue 组件注册 | 基本使用和组件嵌套...

    来源 | https://xueyuanjun.com/post/21929除了前面介绍的基本语法之外,Vue.js 还支持通过组件构建复杂的功能模块,组件可以称得上是 Vue.js 的灵魂,是 Vu ...

  3. 全栈入门_启动数据栈入门包(2020)

    全栈入门 I advise a lot of people on how to build out their data stack, from tiny startups to enterprise ...

  4. 计算机视觉python入门_计算机视觉应该怎样入门?

    自学了一段时间计算机视觉(Computer Vision),下文简称:CV.内容以基本概念为主,形式以看书为主,跟着敲代码为辅.起因:因工作中会涉及到交通物流风险管理.出险理赔材料审查等内容,会涉及到 ...

  5. 儿童编程python入门_儿童编程python入门

    经常会有小朋友问我,"我想做个黑客,我该学什么编程语言?",或者有的小朋友会说:"我要学c,我要做病毒".其实对于这些小朋友而言他们基本都没有接触过编程语言,只 ...

  6. 工业机器人编程语言入门_人工智能和机器学习入门的5种编程语言

    工业机器人编程语言入门 如果您对人工智能和机器学习领域感兴趣,那么您可能正在计划在令人兴奋和动态的编程世界中前进的道路. 但是,如果将来看到AI和机器学习,应该学习哪些语言? 有这么多种选择,您需要在 ...

  7. unity入门_探索Unity MARS入门模板

    unity入门 Starter Templates are predesigned, customizable building blocks created to help AR developer ...

  8. 谈一谈人工智能怎么入门_手把手教你入门

    要问现在的科技界什么最火?答案八九不离十是人工智能,机器学习,深度学习等等.有人说人工智能的未来是泡沫,可是公司门口的指纹门禁,手机拍照时的人脸聚焦,居家使用的扫地机器人,凡此种种,这些都是人工智能的 ...

  9. python机器人编程教程入门_机器人操作系统(ROS)入门必备:机器人编程一学就会

    本书是针对机器人操作系统(ROS)初学者的入门教程,从基础的如何安装ROS,到ROS的框架介绍和C/C++.Python编程基础概念介绍,直至完整搭建一个机器人项目,每一个部分都有详细的操作过程和相应 ...

最新文章

  1. 面试大厂背怼!这都搞不定,你只能做“搬运工”!
  2. 卷积网络基础知识---Depthwise Convolution Pointwise Convolution Separable Convolution
  3. MySQL使用可重复读作为默认隔离级别的原因
  4. 白话Elasticsearch61-进阶篇之基于Term Vectors深入探查数据的情况
  5. Python函数的递归调用
  6. DDD领域模型自动生成?
  7. python 指针_C++的动态内存:C++的指针
  8. 1053. 住房空置率 (20)-PAT乙级真题
  9. lj245a引脚功能图_CA3140中文资料-引脚图及功能
  10. php op array,PHP手册 - Compile a string of PHP code and return the resulting op array
  11. B2C商城系统源码 单商户B2C商城系统源码
  12. HYSPLIT 模型 传输轨迹 使用指南
  13. (NCRE网络技术)IP地址规划设计技术-知识点
  14. Java--获取xml头encoding编码方式
  15. ipad上写代码???阿里云+vscode-server助你一臂之力
  16. 【设计开发命名必备】英语单词缩写规则
  17. java 图片去水印_如何用java去除图片水印?
  18. pdf转换器电脑版免费,好用的办公操作软件集合
  19. java虚拟机最新安卓版apk
  20. PDF如何生成电子书分享

热门文章

  1. 安装CentOS6.8并配置网络图文解说亲测全过程
  2. 假如不工作了,你还有源源不断的收入吗?
  3. scrapy从安装到爬取煎蛋网图片
  4. 前端之sublime text配置
  5. springboot集成jsp
  6. 8597 石子划分问题 dpdp,只考虑第一次即可
  7. async 和 await的前世今生 (转载)
  8. Apache的虚拟主机配置
  9. RandomForestClassifier(随机森林检测每个特征的重要性及每个样例属于哪个类的概率)...
  10. 今天开通了博客园帐号