express-cli入门_使用Express.js入门
express-cli入門(mén)
by Victor Ofoegbu
由Victor Ofoegbu
使用Express.js入門(mén) (Getting off the ground with Express.js)
使用Node.js框架編寫(xiě)Web應(yīng)用 (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.
一個(gè)常見(jiàn)的現(xiàn)實(shí)時(shí)刻是,當(dāng)您開(kāi)發(fā)許多需要相同或相同功能的應(yīng)用程序時(shí)。 現(xiàn)在很明顯,復(fù)制和粘貼代碼是不可擴(kuò)展的—您需要一種為靈活性,最小化和可重用性而設(shè)計(jì)的工具。
That’s where Express sits in the MERN stack. It’s a Node.js framework for building scalable web applications.
這就是Express位于MERN堆棧中的位置。 這是一個(gè)用于構(gòu)建可伸縮Web應(yīng)用程序的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框架構(gòu)建Web應(yīng)用程序。 我們將研究數(shù)據(jù)庫(kù)集成,會(huì)話和cookie,模板引擎以鞏固我們的工作流程,最后是生產(chǎn)和安全方面的問(wèn)題。
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,并且您應(yīng)該對(duì)Node.js和JavaScript具有基本的了解。 如果您不熟悉Node.js,這是我的最后一篇文章: 您唯一需要的NodeJs簡(jiǎn)介 。 這是開(kāi)始深入研究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構(gòu)建,他從Ruby on Rails框架Sinatra獲得了靈感。 Express的最新版本是4.16.1。 Express 4通過(guò)放開(kāi)一些開(kāi)發(fā)人員并不總是使用的模塊而變得更輕便。 因此,他們可以僅在需要時(shí)輕松導(dǎo)入它們。 有道理吧?
To get started with Express, you need to install it and require it in your program.
要開(kāi)始使用Express,您需要安裝它并在程序中require它。
1) Create a folder called express-app, cd into it and hit npm init. This creates our package.json file.
1)創(chuàng)建一個(gè)名為express-app的文件夾,將其放入cd ,然后單擊npm init 。 這將創(chuàng)建我們的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安裝到項(xiàng)目中。 雙破折號(hào)save標(biāo)志基本上意味著我們將其添加到package.json文件中。
3) On the root of our express-app folder, create a server.js file and copy this inside.
3)在我們express-app文件夾的根目錄中,創(chuàng)建一個(gè)server.js文件并將其復(fù)制到其中。
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');}); //綁定服務(wù)器到端口(3000)app.listen(3000,()=> console.log('express服務(wù)器從端口300開(kāi)始'));
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 。 前往瀏覽器并訪問(wèn)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模塊??。 如果您很觀察,您一定已經(jīng)注意到我們不需要像純Node.js應(yīng)用程序中那樣的http模塊。 那是因?yàn)镋xpress需要它,所以我們不需要再做一次。
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.
當(dāng)我們r(jià)equire ('express') ,導(dǎo)出到我們的是一個(gè)函數(shù),因此我們基本上可以直接調(diào)用它并將其分配給app變量。 在這一點(diǎn)上,在我們真正處理請(qǐng)求之前,什么都不會(huì)起作用。 這被稱為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操作的基本動(dòng)詞(例如GET,POST,PUT和DELETE)。 在此處的示例中,我們執(zhí)行一個(gè)app.get()方法來(lái)處理對(duì)服務(wù)器的獲取請(qǐng)求。 它有兩個(gè)參數(shù):請(qǐng)求的path和處理請(qǐng)求的回調(diào)。
If you didn’t get this, I’ll explain more.
如果您不明白這一點(diǎn),我將進(jìn)一步說(shuō)明。
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.
路徑是計(jì)算機(jī)上資源的地址。 回調(diào)是作為參數(shù)傳遞給另一個(gè)函數(shù)的函數(shù),當(dāng)某些情況發(fā)生時(shí)將調(diào)用該函數(shù)。
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.
在這里,我們添加了一個(gè)單擊p時(shí)觸發(fā)的回調(diào)。 看到? 這很容易。
On the last line of server.js, we listen at port 3000 and console.log when we start the server.
在server.js的最后一行,我們?cè)趩?dòng)服務(wù)器時(shí)偵聽(tīng)端口3000和console.log。
I bet you can’t write apps with that. Let’s get meaty.
我敢打賭你不能用它編寫(xiě)應(yīng)用程序。 讓我們變得多肉。
在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).
路由是指分配功能以響應(yīng)用戶的請(qǐng)求。 Express路由器基本上是中間件(這意味著它們可以訪問(wèn)request和response對(duì)象并為我們做一些繁重的工作)。
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動(dòng)詞中的任何一個(gè)。
We can add as many callbacks as we desire. See an example here:
我們可以根據(jù)需要添加任意數(shù)量的回調(diào)。 在這里查看示例:
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.
轉(zhuǎn)到終端或命令提示符,然后單擊node server.js 。 您會(huì)看到在將響應(yīng)發(fā)送到瀏覽器之前, sayHello函數(shù)將觸發(fā)。
The sayHello function takes three arguments (request, response, and next).
sayHello函數(shù)采用三個(gè)參數(shù)( request , response和next )。
The next()function, when called, moves control to the next middleware or route.
調(diào)用next()函數(shù)時(shí),會(huì)將控制權(quán)移至下一個(gè)中間件或路由。
請(qǐng)求和響應(yīng)對(duì)象 (The request and response objects)
The request object contains information about the incoming request. Here are the most useful properties and methods:
request對(duì)象包含有關(guān)傳入請(qǐng)求的信息。 以下是最有用的屬性和方法:
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變量存儲(chǔ)一個(gè)名為GET請(qǐng)求參數(shù)的對(duì)象。 例如,清除您的server.js文件并將其粘貼到內(nèi)部:
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運(yùn)行它,然后轉(zhuǎn)到瀏覽器并運(yùn)行: 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獲取變量并將其發(fā)送到瀏覽器。 關(guān)鍵是request.params是一個(gè)包含所有那些GET參數(shù)的對(duì)象。 注意參數(shù)前的冒號(hào)。 它們將路由參數(shù)與常規(guī)路由路徑區(qū)分開(kāi)。
The request.body property stores POST form parameters.
request.body屬性存儲(chǔ)POST表單參數(shù)。
The request.query property is used to extract the GET form data. Here’s an example of that:
request.query屬性用于提取GET表單數(shù)據(jù)。 這是一個(gè)例子:
1) Create another folder called express-query, and then create two files: server.jsand form.html. Paste this into server.js :
1)創(chuàng)建另一個(gè)名為express-query文件夾,然后創(chuàng)建兩個(gè)文件: 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)將其復(fù)制到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運(yùn)行代碼,命中l(wèi)ocalhost:3000 ,然后在瀏覽器中填寫(xiě)并提交表單。 提交表單后,您填寫(xiě)的數(shù)據(jù)將記錄到控制臺(tái)。
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保留服務(wù)器接收到的請(qǐng)求的鍵/對(duì)值。 服務(wù)器和客戶端利用標(biāo)頭來(lái)傳達(dá)其兼容性和約束。
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'])保存一系列數(shù)據(jù)格式,并返回瀏覽器更喜歡收集數(shù)據(jù)的格式。我們?cè)谔幚鞟jax表單時(shí)也會(huì)看到這一點(diǎn)。
request.url stores data about the URL of the request.
request.url 存儲(chǔ)有關(guān)請(qǐng)求URL的數(shù)據(jù)。
request.ip: holds the IP (Internet protocol) address of the browser requesting for information.
request.ip:保存請(qǐng)求信息的瀏覽器的IP(Internet協(xié)議)地址。
The response object also ships with some convenient methods to get useful information about the outgoing request.
response對(duì)象還附帶了一些便捷的方法來(lái)獲取有關(guān)傳出請(qǐng)求的有用信息。
response.send(message) sends its argument to the browser.
response.send(message) 將其參數(shù)發(fā)送到瀏覽器。
response.json() sends its argument as data to the browser in JSON format.
response.json() 將其參數(shù)作為數(shù)據(jù)以JSON格式發(fā)送到瀏覽器。
response.cookie(name,value,duration) provides an interface to set cookies on browsers. We’ll talk about cookies too.
response.cookie(name,value,duration) 提供了在瀏覽器上設(shè)置Cookie的界面。 我們也將談?wù)揷ookie。
response.redirect([redirect status], url) redirects the browser to the specified URL with the optional status.
response.redirect([redirect status], url)將瀏覽器重定向到具有可選狀態(tài)的指定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})將視圖呈現(xiàn)給瀏覽器,并獲取一個(gè)包含路由器可能需要的數(shù)據(jù)的對(duì)象。 當(dāng)我們看到視圖時(shí),您會(huì)更好地理解它。
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) 設(shè)置標(biāo)題值。 但是您不想這樣做,因?yàn)樗鼤?huì)妨礙瀏覽器的工作。
response.status(status)sets the status of a particular response (404, 200, 401 and so forth).
response.status(status)設(shè)置特定響應(yīng)的狀態(tài)(404、200、401等)。
You don’t have to memorize all these. As we use them, you’ll subconsciously master them.
您不必記住所有這些。 當(dāng)我們使用它們時(shí),您將下意識(shí)地掌握它們。
快速路由器 (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,我們可以將我們的應(yīng)用程序分解為多個(gè)片段,這些片段可以具有自己的Express實(shí)例。 我們可以將它們以非常干凈和模塊化的方式整合在一起。
Let’s take for example. These four random URLs:
讓我們舉個(gè)例子。 這四個(gè)隨機(jī)網(wǎng)址:
localhost:3000/users/john
本地主機(jī):3000 / users / john
localhost:3000/users/mark
本地主機(jī):3000 /用戶/標(biāo)記
localhost:3000/posts/newpost
本地主機(jī):3000 / posts / newpost
localhost:3000/api
本地主機(jī):3000 / api
Our normal approach of doing this with Express would be:
使用Express進(jìn)行此操作的正常方法是:
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.
此時(shí),此模式?jīng)]有任何問(wèn)題。 但是它有潛在的錯(cuò)誤。 當(dāng)我們的路線基本上只有五條時(shí),就沒(méi)什么問(wèn)題了。 但是,當(dāng)事情發(fā)展并且需要大量功能時(shí),將所有代碼放入我們的server.js中并不是我們想要做的。
我們應(yīng)該讓路由器為我們做到這一點(diǎn) (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:
在我們項(xiàng)目的根目錄中創(chuàng)建一個(gè)名為react-router的文件夾,在其中創(chuàng)建一個(gè)文件,并將其basic_router.js 。 將此權(quán)限復(fù)制到:
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.
我們基本上是在創(chuàng)建Express的另一個(gè)實(shí)例。 這次,我們調(diào)用Express的Router()函數(shù)。 可以直接調(diào)用express()作為一個(gè)函數(shù)(如在server.js ),也可以調(diào)用express.Router() 。 這是因?yàn)镋xpress是作為函數(shù)導(dǎo)出的,在JavaScript中,函數(shù)也是對(duì)象。
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應(yīng)用。 但是我們不將其綁定到任何端口。 router對(duì)象包含我們定義的所有路由,因此我們僅導(dǎo)出該對(duì)象,因此程序的其他部分也可以使用它。
We create our main server.js, and add it as a middleware. Yes middlewares make work easier, remember?
我們創(chuàng)建主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.
現(xiàn)在運(yùn)行這個(gè)。 導(dǎo)航到localhost:3000/user/john和localhost:3000/user/mark 。 看到? 在這一點(diǎn)上,事情很容易歸類。
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:
我們可以針對(duì)其他所有路線執(zhí)行此操作。 為我們的API創(chuàng)建另一個(gè)文件。 我們將其稱為api_route.js 。 將此權(quán)限復(fù)制到:
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:
現(xiàn)在,回到我們的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.
這些信息足以構(gòu)建基本的Web應(yīng)用程序路由。
模板引擎 (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.
在大多數(shù)情況下,您對(duì)網(wǎng)站的網(wǎng)頁(yè)數(shù)量不確定。 這意味著您希望保持事物的靈活性,可重用性和清潔性。
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?
假設(shè)您有一個(gè)頁(yè)腳,可能要在每個(gè)頁(yè)面上使用。 如果只是將其放在文件中并在每一頁(yè)上嵌入一行代碼,那會(huì)不會(huì)很酷? 或者,如何丟失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.
目前有很多模板引擎。 但是我們將使用把手來(lái)查看模板的工作方式。 幸運(yùn)的是,幾乎所有模板引擎都適用相同的原理-只是語(yǔ)法上的改變。
To make use of Handlebars, we install it.
為了利用車把,我們安裝了它。
npm install --save express-handlebarsrequire it in your file and configure your app to use it like so:
在您的文件中require它,并配置您的應(yīng)用程序以使其使用,如下所示:
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進(jìn)行基本渲染:
Create a folder called express-handlebars, create a views folder, and inside the views folder create another folder called layouts.
創(chuàng)建一個(gè)名為express-handlebars的文件夾,創(chuàng)建一個(gè)views文件夾,然后在views文件夾內(nèi)創(chuàng)建另一個(gè)名為layouts文件夾。
2) Create a server.js file and paste this inside:
2)創(chuàng)建一個(gè)server.js文件并將其粘貼到內(nèi)部:
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(‘a(chǎn)bout’,{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文件夾中,創(chuàng)建一個(gè)文件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)接下來(lái),我們將創(chuàng)建單獨(dú)的視圖。 在views文件夾中,創(chuàng)建兩個(gè)文件home.hbs和about.hbs 。 將以下內(nèi)容粘貼到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.
在終端中執(zhí)行一個(gè)node server.js ,然后在瀏覽器中點(diǎn)擊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并創(chuàng)建一個(gè)defaultLayout ,將其分配給main.hbs 。 這意味著我們所有的視圖都將呈現(xiàn)到main.hbs布局中。
Take a look at the server.js. Just a few things changed right? Let’s start with these two lines:
看一看server.js 。 只是幾件事改變了吧? 讓我們從這兩行開(kāi)始:
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?
第一行將應(yīng)用程序引擎設(shè)置為hbs.engine ,第二行將視圖引擎屬性設(shè)置為車把。 很直接吧?
The routes in our server.js are also a little different. Here’s the culprit:
我們的server.js中的路由也有所不同。 這是罪魁禍?zhǔn)?#xff1a;
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()將純文本發(fā)送到瀏覽器時(shí), render()在views文件夾中查找第一個(gè)參數(shù),并將其呈現(xiàn)到瀏覽器。 大多數(shù)時(shí)候,我們可能也想將動(dòng)態(tài)內(nèi)容傳遞給視圖。 我們給render方法一個(gè)對(duì)象作為第二個(gè)參數(shù)。 該對(duì)象包含要在視圖內(nèi)部傳遞的數(shù)據(jù)的鍵和值。
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}}被視圖傳遞的內(nèi)容所代替。 在我們的例子中, {title: 'Home'} 。 我們可以向視圖傳遞任意數(shù)量的值。 只需將其添加為對(duì)象的屬性即可。
When we do a response.render(), Express knows where to get the files we ask for. Let’s look into the about.hbs.
當(dāng)我們執(zhí)行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:
該文件的內(nèi)容替換了我們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.
如果您要問(wèn)為什么我們?cè)趝{title}}中使用兩個(gè)大括號(hào),而在{{{body}}}中使用三個(gè)大括號(hào),那么您的方向正確。
When we use two braces, we spit out everything, even the HTML tags (unescaped). Here’s what I mean.
當(dāng)我們使用兩個(gè)大括號(hào)時(shí),我們吐出了所有內(nèi)容,甚至包括HTML標(biāo)記(未轉(zhuǎn)義)。 這就是我的意思。
If the content we want to send to the browser is <b>Hello world</b>, with two braces, Express will render it as <b>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).
如果我們要發(fā)送給瀏覽器的內(nèi)容是<b>Hello wor </ b>,帶有兩個(gè)大括號(hào),Express會(huì)將其ender it as <b&g t; Hello world </ b>。 如果我們使用三個(gè)大括號(hào),Express將會(huì)理解我們想要一個(gè)純文本并將其呈現(xiàn)為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中模板引擎的工作方式。 車把提供一頁(yè)文檔。 我認(rèn)為這是一個(gè)不錯(cuò)的起點(diǎn)。
在Express中呈現(xiàn)靜態(tài)內(nèi)容 (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.
您是否想到過(guò)將CSS,JavaScript文件和圖像存儲(chǔ)在何處? 好吧,Express提供了一個(gè)中間件,使服務(wù)器知道在哪里可以找到靜態(tài)內(nèi)容。
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。語(yǔ)句之后的server.js頂部。 __dirname包含從中運(yùn)行程序的路徑。
If you didn’t get that, try this.
如果沒(méi)有得到,請(qǐng)嘗試此操作。
Delete everything on your server.js, and put this inside:
刪除server.js上的所有內(nèi)容,并將其放入其中:
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.
轉(zhuǎn)到命令行,然后運(yùn)行node server.js 。 它向您顯示正在運(yùn)行的文件節(jié)點(diǎn)的路徑。
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:
我們存儲(chǔ)靜態(tài)內(nèi)容的位置取決于我們。 我們可能想將其命名為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.
中間件是封裝功能的功能。 它們對(duì)HTTP請(qǐng)求執(zhí)行操作,并為我們提供了高級(jí)界面以對(duì)其進(jìn)行自定義。 大多數(shù)中間件采用三個(gè)參數(shù): request , response對(duì)象和next函數(shù)。 在錯(cuò)誤處理中間件中,還有一個(gè)附加參數(shù): err對(duì)象,它可以告訴我們錯(cuò)誤并將其傳遞給其他中間件。
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)將中間件添加到服務(wù)器中。 同樣重要的是要注意,中間件的使用順序與添加時(shí)相同。 如果您不了解,我稍后將為您提供示例。
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.
通過(guò)此定義,我們還可以將路由函數(shù)app.get() , app.post()等視為中間件,只是將它們應(yīng)用于特定的HTTP動(dòng)詞請(qǐng)求。 您可能還會(huì)發(fā)現(xiàn)有趣的是,有一條app.all()路由應(yīng)用于所有HTTP請(qǐng)求,而不考慮它們是GET,POST還是其他請(qǐng)求。
//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.
路由處理程序采用兩個(gè)參數(shù),即匹配路徑和要執(zhí)行的中間件。
app.get('/',(request,,response)=>{response.send(‘Hello world’); });If the path is left out, the middleware applies to every GET request.
如果路徑被忽略,則中間件將應(yīng)用于每個(gè)GET請(qǐng)求。
//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.
在上面的示例中,一旦我們發(fā)送GET請(qǐng)求,我們的服務(wù)器就會(huì)通過(guò)發(fā)送'Hello world'消息來(lái)響應(yīng)瀏覽器,然后終止直到有另一個(gè)請(qǐng)求。
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.
但是我們可能希望調(diào)用多個(gè)中間件。 有一種方法可以做到這一點(diǎn)。 還記得我們的next功能嗎? 我們可以利用它來(lái)將控制推到另一個(gè)中間件。
Let’s see how this works. Copy and paste this code into our server.js:
讓我們看看它是如何工作的。 將此代碼復(fù)制并粘貼到我們的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并查看終端。 轉(zhuǎn)到瀏覽器并打開(kāi)localhost:3000 。 再次查看您的控制臺(tái),您會(huì)看到類似的內(nèi)容。
Express server started at port 3000 processing for data for / The response.send will terminate the requestOur 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.
每當(dāng)收到請(qǐng)求時(shí),我們的第一個(gè)中間件就會(huì)執(zhí)行。 它將一些內(nèi)容寫(xiě)入控制臺(tái)并調(diào)用next()函數(shù)。 調(diào)用next()函數(shù)告訴Express不要終止request對(duì)象,而是將控制權(quán)發(fā)送給下一個(gè)中間件。 每當(dāng)我們編寫(xiě)中間件而沒(méi)有調(diào)用next函數(shù)時(shí),Express都會(huì)終止request對(duì)象。
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.
在第二個(gè)中間件中,我們將next()函數(shù)作為參數(shù)傳遞,但是我們從不調(diào)用它。 這將終止request對(duì)象,并且永遠(yuǎn)不會(huì)調(diào)用第三個(gè)中間件。 請(qǐng)注意,如果我們從不向第二個(gè)中間件中的瀏覽器發(fā)送任何內(nèi)容,則客戶端最終將超時(shí)。
Here are some useful middleware in Express.js:
這是Express.js中一些有用的中間件:
Morgan — log each request
Morgan-記錄每個(gè)請(qǐng)求
CORS — enables Cross Origin Request Sharing
CORS —啟用跨源請(qǐng)求共享
body-parser — a middleware to parse the request.body in Express apps
body-parser —在Express應(yīng)用程序中解析request.body的中間件
Multer — Node.js middleware for handling multipart/form-data
Multer —用于處理multipart/form-data Node.js中間件
session — simple session middleware for Express.js
會(huì)話 — Express.js的簡(jiǎn)單會(huì)話中間件
errorhandler — development-only error handler middleware
errorhandler —僅開(kāi)發(fā)錯(cuò)誤處理程序中間件
serve-favicon — favicon serving middleware
serve-favicon —提供服務(wù)的favicon中間件
csurf — Node.js CSRF protection middleware
csurf — Node.js CSRF保護(hù)中間件
Passport — Simple, unobtrusive authentication
護(hù)照 -簡(jiǎn)單,簡(jiǎn)單的身份驗(yàn)證
Merror — A RESTful-friendly Express Middleware for HTTP error handling and error responses
Merror — RESTful友好的Express中間件,用于HTTP錯(cuò)誤處理和錯(cuò)誤響應(yīng)
Expressa — express middleware for easily making REST APIs
Expressa —用于輕松制作REST API的快速中間件
在Express中處理表單數(shù)據(jù) (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.
網(wǎng)絡(luò)的主要功能是通信。 Express為我們提供了了解客戶要求以及如何正確響應(yīng)的工具。
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基本上有兩個(gè)地方可以存儲(chǔ)客戶端數(shù)據(jù)。 request.querystring(用于GET請(qǐng)求)和request.body(用于POST請(qǐng)求) 。 在客戶端,使用POST方法進(jìn)行表單提交是理想的,因?yàn)榇蠖鄶?shù)瀏覽器都會(huì)限制querystring的長(zhǎng)度,并且會(huì)丟失其他數(shù)據(jù)。 如果您不知道查詢字符串是什么,則它是URL后面的部分,其中包含數(shù)據(jù),并且不適合您的路由路徑系統(tǒng)。 如果您不太了解查詢字符串是什么,請(qǐng)看以下示例:
facebook.com/users?name=Victor&age=100&occupation=whateverFrom the point where the question mark begins is called the query string. It passes data to the server but exposes it in the URL.
從問(wèn)號(hào)開(kāi)始的地方稱為查詢字符串。 它將數(shù)據(jù)傳遞到服務(wù)器,但在URL中公開(kāi)。
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.
保持查詢字符串盡可能整潔也是一個(gè)好習(xí)慣。 使用GET請(qǐng)求發(fā)送大數(shù)據(jù)會(huì)使查詢字符串混亂。
Let’s see a demo. We’ll take some data from our client via GET and send it back to them.
讓我們看一個(gè)演示。 我們將通過(guò)GET從客戶那里獲取一些數(shù)據(jù),并將其發(fā)送回給他們。
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:
創(chuàng)建一個(gè)文件夾,將其稱為form-data ,并在其中創(chuàng)建兩個(gè)文件: 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.
運(yùn)行node server.js ,轉(zhuǎn)至localhost:3000 ,填寫(xiě)表格并提交。
Here’s what the result would look like.
結(jié)果如下所示。
In our server.js file here, we have to two GET routes. One for localhost:3000 and localhost:3000/process.
在這里的server.js文件中,我們必須有兩個(gè)GET路由。 一個(gè)用于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.
進(jìn)入您的控制臺(tái)。 您會(huì)看到一個(gè)對(duì)象。 這證明我們的request.query是一個(gè)包含所有查詢及其值的對(duì)象。
{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頁(yè)面上查看我們的表單,您會(huì)發(fā)現(xiàn)我們的表單具有action和method屬性。 action屬性指定應(yīng)處理表單數(shù)據(jù)的頁(yè)面或路由(在這種情況下為“過(guò)程”)。 提交表單后,它將GET請(qǐng)求發(fā)送到process路由,表單的內(nèi)容作為querystring數(shù)據(jù)。
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文件還處理對(duì)流程路徑的請(qǐng)求,并將從form.html傳遞的數(shù)據(jù)發(fā)送到瀏覽器和控制臺(tái)。
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方法處理此問(wèn)題。 現(xiàn)在該清除我們的server.js文件了。 將此代碼復(fù)制并粘貼到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.
如果仔細(xì)觀察,我們要做的第一件事就是需要并使用body-parser 。 Body-parser是一個(gè)中間件,可在我們的request.body提供POST數(shù)據(jù)。 請(qǐng)記住,沒(méi)有body-parser中間件, request.body將無(wú)法工作。
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.
您可能還會(huì)注意到我們同時(shí)具有GET和POST路由處理程序。 GET中間件顯示表單,而POST中間件對(duì)其進(jìn)行處理。 由于它們使用的方法不同,因此它們都可能使用一條路由路徑。
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.
對(duì)于第一個(gè)示例,我們無(wú)法執(zhí)行此操作,因?yàn)槲覀兊谋韱畏椒ㄊ荊ET。 顯然,對(duì)于相同的路由,您不能有兩個(gè)GET請(qǐng)求,并且它們都必須將數(shù)據(jù)發(fā)送到瀏覽器。 這就是為什么我們的第一個(gè)示例在/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表單非常簡(jiǎn)單。 Express為我們提供了request.xhr屬性,以告知我們是否通過(guò)AJAX發(fā)送了請(qǐng)求。 我們可以將其與前面討論的request.accepts()方法結(jié)合使用。 它可以幫助我們確定瀏覽器需要哪種格式的數(shù)據(jù)。如果客戶端喜歡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并發(fā)送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.
這里沒(méi)有太多更改-如果請(qǐng)求是使用AJAX進(jìn)行的,我們只是添加了一種方法來(lái)審核。
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方法將請(qǐng)求設(shè)為AJAX請(qǐng)求。 我們鏈接到j(luò)Query CDN。 在腳本標(biāo)簽中,我們?yōu)镾ubmit事件附加了一個(gè)事件處理程序。 當(dāng)我們這樣做時(shí),我們防止了重新加載頁(yè)面的默認(rèn)行為。
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()方法發(fā)出AJAX請(qǐng)求。 服務(wù)器以帶有message屬性的對(duì)象作為響應(yīng),然后將其附加到空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,我曾經(jīng)寫(xiě)過(guò)一些有關(guān)AJAX的文章。 查看它們: AJAX和jQuery的異步請(qǐng)求的輕松 介紹 。
Node.js應(yīng)用程序中的數(shù)據(jù)庫(kù) (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應(yīng)用程序的數(shù)據(jù)庫(kù)系統(tǒng)。 這并不完全排除使用其他數(shù)據(jù)庫(kù)的可能性。 我們將研究MongoDB,但是您可以選擇任何一個(gè)。
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.
文檔替換了關(guān)系數(shù)據(jù)庫(kù)(如MySQL)中的行。 在MongoDB和其他基于文檔的數(shù)據(jù)庫(kù)中,數(shù)據(jù)以對(duì)象格式存儲(chǔ)和檢索。 這意味著我們可以擁有深層嵌套的結(jié)構(gòu)。
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中的對(duì)象,則無(wú)法驗(yàn)證對(duì)象屬性的值是特定類型。 這就是我的意思:
const obj = { text : 1234}
const obj = { text : 1234}
There’s no way to make sure the value of textis a string.
無(wú)法確保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).
幸運(yùn)的是,有貓鼬。 Mongoose允許您定義用于強(qiáng)烈驗(yàn)證數(shù)據(jù)并確保它們與MongoDB中的對(duì)象或文檔匹配的架構(gòu)。 貓鼬是一個(gè)對(duì)象文檔映射器(ODM)。
An introduction to Mongoose is a nice place to start exploring and working with Mongoose.
貓鼬入門(mén)是開(kāi)始探索和使用貓鼬的好地方。
Express中的會(huì)話和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是無(wú)狀態(tài)的。 意味著瀏覽器或服務(wù)器發(fā)送的任何請(qǐng)求或響應(yīng)分別不保留有關(guān)先前或?qū)?lái)的請(qǐng)求和響應(yīng)的信息(狀態(tài))。 每個(gè)單個(gè)請(qǐng)求都具有引發(fā)新服務(wù)器響應(yīng)所需要的一切。
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.
但是服務(wù)器必須有一種方法來(lái)記住客戶端,因?yàn)榭蛻舳嗽跒g覽網(wǎng)站時(shí)不必在每個(gè)頁(yè)面上都輸入密碼。
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.
網(wǎng)絡(luò)已經(jīng)足夠創(chuàng)新,可以使用cookie和會(huì)話。 Cookies基本上是存儲(chǔ)在客戶端計(jì)算機(jī)上的小文件。 客戶端發(fā)送請(qǐng)求時(shí),服務(wù)器使用它來(lái)識(shí)別請(qǐng)求。 服務(wù)器更像護(hù)照,然后會(huì)知道是他們并應(yīng)用他們的所有首選項(xiàng)。
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?
因此,想法是將文件存儲(chǔ)在客戶端計(jì)算機(jī)上。 雖然這不是一個(gè)壞主意,但我們要確保我們不會(huì)通過(guò)存儲(chǔ)大量數(shù)據(jù)來(lái)濫用用戶的存儲(chǔ)。 在另一方面,我們了解到,如果我們想使事情變得更難以猜測(cè)和更加安全,那么我們將使其變得更長(zhǎng),更復(fù)雜。 我們?nèi)绾瓮瑫r(shí)實(shí)現(xiàn)這兩個(gè)目標(biāo)?
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.
人們提出了會(huì)議。 因此,會(huì)話的想法是,服務(wù)器將標(biāo)識(shí)符存儲(chǔ)在cookie中(一個(gè)小字符串),而不是將所有信息存儲(chǔ)在客戶端的cookie中。 當(dāng)客戶端發(fā)送請(qǐng)求時(shí),服務(wù)器將使用該唯一字符串并將其與服務(wù)器上用戶的數(shù)據(jù)進(jìn)行匹配。 這樣,我們可以存儲(chǔ)任何數(shù)量的數(shù)據(jù),并且仍然記住用戶。
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.
我無(wú)法最好地深入解釋這一點(diǎn)。 但是有人在這里做得更好: 快速會(huì)議 。
Express應(yīng)用程序中的安全性 (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.
默認(rèn)情況下,網(wǎng)絡(luò)不受保護(hù)。 數(shù)據(jù)包是通過(guò)網(wǎng)絡(luò)發(fā)送數(shù)據(jù)的方式。 這些數(shù)據(jù)包默認(rèn)情況下是未加密的。 考慮網(wǎng)絡(luò)安全時(shí),首先要確保這些數(shù)據(jù)包的安全。
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 :這不是一個(gè)新詞! 就像您可能已經(jīng)猜到的那樣,HTTP和HTTPS之間的區(qū)別是S(安全性)。 HTTPS會(huì)對(duì)通過(guò)網(wǎng)絡(luò)傳輸?shù)臄?shù)據(jù)包進(jìn)行加密,因此人們不會(huì)對(duì)其進(jìn)行惡意處理。
那么我該如何獲取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.
冷靜,讓我們慢慢來(lái)。 要獲取HTTPS,您需要聯(lián)系證書(shū)頒發(fā)機(jī)構(gòu)(CA)。 HTTPS基于具有公共密鑰證書(shū)(有時(shí)稱為SSL)的服務(wù)器。 CA將證書(shū)分配給合格的服務(wù)器。 您還必須了解,CA會(huì)生成在安裝瀏覽器時(shí)安裝的根證書(shū)。 因此,瀏覽器也可以輕松地通過(guò)證書(shū)與服務(wù)器通信。
Good news: Anybody can make their own certificates.
好消息 :任何人都可以制作自己的證書(shū)。
Bad news: The browsers can’t recognize those certificates because they weren’t installed as root certificates.
壞消息 :瀏覽器無(wú)法識(shí)別這些證書(shū),因?yàn)樗鼈儾皇亲鳛楦C書(shū)安裝的。
Impossible: You can’t configure all the browsers in the world during installation to recognize your certificate.
不可能 :您無(wú)法在安裝過(guò)程中配置世界上所有的瀏覽器來(lái)識(shí)別您的證書(shū)。
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.
我可以告訴你現(xiàn)在在想什么。 您在考慮可以創(chuàng)建自己的用于測(cè)試和開(kāi)發(fā)的證書(shū)并在生產(chǎn)中獲得證書(shū)。 好吧,這很聰明而且可能。
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.
瀏覽器會(huì)向您發(fā)出警告,但是您已經(jīng)知道了問(wèn)題,因此不會(huì)有太大的問(wèn)題。 這里有一個(gè)職位是引導(dǎo)您完成創(chuàng)建您自己的證書(shū)。
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
如何在不引起瀏覽器隱私錯(cuò)誤的情況下 在本地設(shè)置HTTPS可能是一件棘手的事情。 即使您確實(shí)設(shè)法將自簽名證書(shū)摔入…… Deliciousbrains.com
Enough talking. Let’s assume you now have the SSL certificate. Here’s how to make it work with your Express app.
聊夠了。 假設(shè)您現(xiàn)在擁有SSL證書(shū)。 這是使其與Express應(yīng)用程序一起使用的方法。
在您的Node應(yīng)用程序中啟用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.
我們需要對(duì)HTTPS使用https模塊。 從證書(shū)頒發(fā)機(jī)構(gòu)獲得我們的憑據(jù)后,我們會(huì)將其作為參數(shù)添加到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).
注意,我們需要http和https. 這是因?yàn)槲覀兿雽?duì)兩者做出回應(yīng)。 在我們的程序中,我們正在使用fs模塊(文件系統(tǒng))。
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密鑰和證書(shū)的存儲(chǔ)路徑。 模塊或其他東西。 觀察到我們正在使用readFileSync 方法,而不是readFile 。 如果您了解Node.js架構(gòu),則可以推斷我們希望在運(yùn)行任何其他代碼行之前同步讀取文件。
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.
異步運(yùn)行此代碼可能會(huì)導(dǎo)致以下情況:需要文件內(nèi)容的代碼某些方面無(wú)法按時(shí)得到。
The last two lines bind the HTTP and HTTPS to two different ports and take different arguments. Why are we doing this?
最后兩行將HTTP和HTTPS綁定到兩個(gè)不同的端口,并采用不同的參數(shù)。 我們?yōu)槭裁催@樣做呢?
At most times, we want our server to still listen to requests with HTTP and maybe redirect them to HTTPS.
在大多數(shù)情況下,我們希望我們的服務(wù)器仍然使用HTTP偵聽(tīng)請(qǐng)求,甚至可以將其重定向到HTTPS。
Note: the default port for HTTPS is 443.
注意 :HTTPS的默認(rèn)端口是443。
To do this basic redirect, we’ll install and require a module express-force-ssl at the top of our program like so:
要執(zhí)行此基本重定向,我們將在程序頂部安裝并需要一個(gè)模塊express-force-ssl ,如下所示:
npm install express-force-sslAnd 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.
現(xiàn)在,我們的服務(wù)器可以有效地處理HTTP和HTTPS請(qǐng)求。
跨站請(qǐng)求偽造(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.
這是您要保護(hù)自己免受傷害的另一件大事。 當(dāng)請(qǐng)求到達(dá)您的服務(wù)器而不是直接來(lái)自用戶時(shí),就會(huì)發(fā)生這種情況。 例如,您在Facebook.com上有一個(gè)活動(dòng)會(huì)話,并且打開(kāi)了另一個(gè)選項(xiàng)卡。 惡意腳本可以在其他站點(diǎn)上運(yùn)行,并向Facebook服務(wù)器發(fā)出請(qǐng)求。
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.
處理此問(wèn)題的一種方法是確保請(qǐng)求僅來(lái)自您的網(wǎng)站。 那很容易。 我們?yōu)橛脩舴峙湟粋€(gè)ID并將其附加到表單,因此當(dāng)他們提交表單時(shí),我們可以匹配該ID并在不匹配時(shí)拒絕訪問(wèn)。
Luckily, there’s a middleware that handles this — csurfmiddleware. Here’s how to use it:
幸運(yùn)的是,有一個(gè)可以處理此csurf中間件csurf中間件。 使用方法如下:
npm install csurfTo 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.
運(yùn)行node server.js ,轉(zhuǎn)到瀏覽器localhost:3000 ,填寫(xiě)表格并提交。 另外,請(qǐng)?jiān)诿钚兄袡z查并查看已記錄的令牌。
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模塊才能工作。 我們配置會(huì)話CSRF并通過(guò)response.render()方法將其傳遞給視圖。
Our view can now append it to the form or any other sensitive request.
現(xiàn)在,我們的視圖可以將其追加到表單或任何其他敏感請(qǐng)求。
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.
那么當(dāng)瀏覽器沒(méi)有從瀏覽器表單中獲取CSRF令牌時(shí)會(huì)發(fā)生什么呢? 它吐出一個(gè)錯(cuò)誤。 確保Express應(yīng)用程序中有錯(cuò)誤處理路線,否則您的應(yīng)用程序可能行為不當(dāng)。
認(rèn)證方式 (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.
減少身份驗(yàn)證問(wèn)題的一個(gè)步驟是讓人們注冊(cè)并使用第三方應(yīng)用程序(Facebook,Twitter,Google等)登錄。 很多人都有這些帳戶,您也可以訪問(wèn)他們的某些數(shù)據(jù),例如電子郵件和用戶名。 諸如passport.js模塊提供了一個(gè)非常優(yōu)雅的界面來(lái)處理這種身份驗(yàn)證。
Here’s the official passport.js documentation. I think it’s a nice place to start.
這是官方的password.js文檔 。 我認(rèn)為這是一個(gè)不錯(cuò)的起點(diǎn)。
Another step to reduce authentication problems is to always encrypt all passwords and decrypt them back when showing them to the users.
減少身份驗(yàn)證問(wèn)題的另一步是,始終加密所有密碼,并在向用戶顯示密碼時(shí)將其解密。
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?
還有一件事。 我在很多網(wǎng)站上都看到了這一點(diǎn)。 他們?yōu)榫W(wǎng)站上的用戶密碼設(shè)置了瘋狂的條件。 我了解他們正在嘗試使密碼更安全,但請(qǐng)考慮一下。 這是誰(shuí)的工作? 開(kāi)發(fā)人員還是用戶?
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.
用戶應(yīng)該至少對(duì)安全問(wèn)題感到困擾。 當(dāng)在密碼上設(shè)置此類條件時(shí),用戶別無(wú)選擇,只能使用他們永遠(yuǎn)不會(huì)記住的密碼。 我知道網(wǎng)絡(luò)越來(lái)越好,我們將找出一種使身份驗(yàn)證更好的方法。
Till then I think we can end this here.
到那時(shí),我認(rèn)為我們可以在這里結(jié)束。
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.
這是很多信息。 但是,您不僅僅需要構(gòu)建可伸縮的Web應(yīng)用程序。 這是一些有見(jiàn)地的書(shū),可用于進(jìn)一步了解Express。
If this was useful, you should follow me on Twitter for more useful stuff.
如果這有用,您應(yīng)該在Twitter上關(guān)注我,以獲取更多有用的信息。
Express in action by Evan Hahn.
快速行動(dòng)由埃文·哈恩 。
Getting MEAN with Express, Mongo, Angular and Node by Simon Holmes.
Simon Holmes通過(guò)Express,Mongo,Angular和Node獲得MEAN 。
翻譯自: https://www.freecodecamp.org/news/getting-off-the-ground-with-expressjs-89ada7ef4e59/
express-cli入門(mén)
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的express-cli入门_使用Express.js入门的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 经常梦到老公出轨离婚预示什么
- 下一篇: 租金 预测_如何预测租金并优化租赁期限,