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路由器基本上是中間件(這意味著它們可以訪問request
和response
對象并為我們做一些繁重的工作)。
Routing in Express follows this basic format:
Express中的路由遵循以下基本格式:
app.VERB(‘path’, callback…);
Where VERB
is any of the GET
, POST
, PUT
, and DELETE
verbs.
VERB
是GET
, POST
, PUT
和DELETE
動詞中的任何一個。
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
函數采用三個參數( request
, response
和next
)。
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.js
and form.html
. Paste this into server.js
:
1)創建另一個名為express-query
文件夾,然后創建兩個文件: server.js
和form.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/john
和localhost: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進行基本渲染:
Create a folder called
express-handlebars
, create aviews
folder, and inside theviews
folder create another folder calledlayouts
.創建一個名為
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.hbs
and about.hbs
. Paste the following inside home.hbs
:
4)接下來,我們將創建單獨的視圖。 在views
文件夾中,創建兩個文件home.hbs
和about.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-handlebars
and 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 wor
ld</b>, with two braces, Express will render it as <b&g
t;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 assets
or 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請求執行操作,并為我們提供了高級界面以對其進行自定義。 大多數中間件采用三個參數: request , response對象和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 GET
request, 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 request
object.
每當收到請求時,我們的第一個中間件就會執行。 它將一些內容寫入控制臺并調用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 appsbody-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.js
和form.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:3000
和localhost: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.html
page, you’ll notice our form has action
and method
attributes. The action
attribute 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 process
route with the content of our form as querystring
data.
如果您在form.html
頁面上查看我們的表單,您會發現我們的表單具有action
和method
屬性。 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.js
file. 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.xhr
property 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 message
property, 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 text
is 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 http
and https.
This is because we want to respond to both. In our program, we’re making use of the fs
module (file-system).
注意,我們需要http
和https.
這是因為我們想對兩者做出回應。 在我們的程序中,我們正在使用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 — csurf
middleware. 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上關注我,以獲取更多有用的信息。
Express in action by Evan Hahn.
快速行動由埃文·哈恩 。
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入門