前端開發(fā)者該如何設(shè)置數(shù)據(jù)庫
最近有人來問我,作為前端開發(fā)人員保存用戶數(shù)據(jù)信息的最簡便的方法是什么。因此我來說明一下如何實(shí)現(xiàn)它。
配置數(shù)據(jù)庫
首先我們須要先有一個(gè)數(shù)據(jù)庫。你可以通過 mlab 獲取一個(gè)免費(fèi)的。注冊之后,在 MongoDB 的部屬表中點(diǎn)擊 新建。 我們要用的是這個(gè)免費(fèi)的沙盒數(shù)據(jù)。
創(chuàng)建數(shù)據(jù)庫之后,我們需要?jiǎng)?chuàng)建一個(gè)賬戶以便于我們進(jìn)行自我驗(yàn)證。點(diǎn)擊數(shù)據(jù)庫名稱,然后點(diǎn)擊 用戶 , 并添加數(shù)據(jù)庫用戶 。 寫下你選擇的之后要用到的用戶名和密碼 。
在數(shù)據(jù)庫頁面的頂部,你能夠看到一個(gè) MongoDB URI 。這是我們數(shù)據(jù)庫的網(wǎng)址。這個(gè)數(shù)據(jù)庫的 URI 相當(dāng)于網(wǎng)頁的 URL 。通常情況下,MongoDB 的 URI 如下:
- mongodb://<dbuser>:<dbpassword>@<host>:<port>/<dbname>
例如,我的:
- mongodb://admin:superSecretPassword@ds111885.mlab.com:11885/medium
設(shè)置服務(wù)器
我們會在后端使用 Node。你可能單擊 這里 克隆我在 Glitch 上的項(xiàng)目,省去自己設(shè)置的麻煩。
我們從 server.js 開始,如下:
- // init project
- const express = require('express'); // the library we will use to handle requests
- const app = express(); // instantiate express
- app.use(require("cors")()) // allow Cross-domain requests
- app.use(require('body-parser').json()) // automatically parses request data to JSON
- // base route
- app.get("/", function (request, response) {
- response.send("TODO") // always responds with the string "TODO"
- });
- // base route
- app.post("/", function (request, response) {
- response.send("TODO") // always responds with the string "TODO"
- });
- app.put("/", function (request, response) {
- response.send("TODO") // always responds with the string "TODO"
- });
- // listen for requests, the process.env.PORT is needed because
- // we are using glitch, otherwise you could have written 80 or whatever
- var listener = app.listen(process.env.PORT, function () {
- console.log('Your app is listening on port ' + listener.address().port);
- });
我們首先導(dǎo)入了 express —— 這個(gè)庫用來處理向我們的服務(wù)器送來的請求。
我們需要 use(require(cors)) 來允許跨域請求。跨域請求是從某個(gè)域名的網(wǎng)站去請求另一個(gè)域名下的服務(wù)。
app.use(require('body-parser').json()) 為自動(dòng)為我們將請求數(shù)據(jù)解析成 JSON。
然后我們向 get 方向傳遞想要處理的路由,以及處理請求的回調(diào)。也就是說只要有人打開網(wǎng)站中的 / 頁面,請求就會被傳遞給那個(gè)回調(diào)來處理。域名部分是隱含的,所以如果你的的域是 http://shiny-koala.glitch.com,路由 /about 就是 http://shiny-koala.glitch.com/about。
確切地說,我說的“打開頁面”是指產(chǎn)生一個(gè)使用 GET 方法發(fā)送給服務(wù)的請求。HTTP 方法只是你發(fā)送給服務(wù)的請求類型,我們只會使用這些:
- GET 方法用于從服務(wù)器獲取資源。比如,打開 Facebook 的時(shí)候,它需要加載 HTML、CSS 和 JavaScript。
- POST 方法用于在服務(wù)器上創(chuàng)建資源。比如在 Facebook 上發(fā)布內(nèi)容,寫在發(fā)布內(nèi)容中的信息使用通過 POST 請求發(fā)送給服 Facebook 務(wù)器。
- PUT 方法用于更新服務(wù)器上的資源。比如,你在修改某篇發(fā)布內(nèi)容的時(shí)候,就使用 PUT 請求將修改的內(nèi)容發(fā)送給 Facebook 服務(wù)器。
app.post 和 app.put 的工作方式和 app.get 很像,但是有足夠合理的理由使用 POST 和 PUT 方法代替 GET。
路由
在你進(jìn)行服務(wù)器開發(fā)時(shí),你需要進(jìn)行一些測試。你可以用簡單的網(wǎng)站 REST test test 或者 Insomnia 應(yīng)用程序去運(yùn)行一下 HTTP 請求。
點(diǎn)擊 顯示 按鈕,來檢查 Glitch 應(yīng)用程序的 URL 。
到目前為止,我們只是用過路由 / 。但是如果我們想對不同的用戶存儲不同的信息,我們就需要給不同的用戶分配一個(gè)不同的路由。
例如: /ZaninAndrea 和 /JohnGreen
現(xiàn)在有一個(gè)難點(diǎn):
我們不可能對每一條路由進(jìn)行編碼,因?yàn)樗皇且粋€(gè)可擴(kuò)展的方法。我們需要的是 路由參數(shù) 。接下來我們只編碼一個(gè)路由:/:user
冒號是在表達(dá)要捕捉任何以/開始的并且只包含字符數(shù)字的路由。
如下例所示:
- /ZaninAndrea 能夠捕捉到
- /Johnny45 能夠捕捉到
- /alex/score 不 能捕捉到
我們可以在變量 request.params.user 中檢索 user
- // base route
- app.get("/:user", function (request, response) {
- response.send(request.params.user)
- });
- // base route
- app.post("/:user", function (request, response) {
- response.send(request.params.user)
- });
- // base route
- app.put("/:user", function (request, response) {
- response.send(request.params.user)
- });
現(xiàn)在服務(wù)器可以響應(yīng)每一個(gè)查詢并顯示查詢的用戶名。
向數(shù)據(jù)庫增加數(shù)據(jù)
我們知道 user 是誰了,現(xiàn)在我們想存儲一些關(guān)于他的信息。
為了查詢數(shù)據(jù)庫,我們會使用 mongodb 庫。你可以用以下兩個(gè)方法安裝:
- npm install mongodb --save
或者如果你使用 Glitch ,你可以切換到 package.json 文件并點(diǎn)擊 Add package 按鈕。
我們加載 mongodb 庫然后存儲 MongoDB URI 到一個(gè)變量中:
- const mongodb = require('mongodb'); // load mongodb
- const uri = process.env.URI;
URI 是很敏感的信息——這是訪問數(shù)據(jù)庫所需的一切。***把 URI 放到一個(gè) .env 文件中,.env 文件中的信息對于其他人是不可見的。
- URI=mongodb://admin:PASSWORD@ds111885.mlab.com:11885/medium
Glitch 會自動(dòng)從 .env 文件中加載變量到 process.env 變量。
數(shù)據(jù)庫的連接是異步的操作,所以我們需要像這樣在回調(diào)中包裝所有服務(wù)器設(shè)置:
- mongodb.MongoClient.connect(uri, function(err, db) {
- // base route
- app.get("/:user", function (request, response) {
- response.send(request.params.user)
- });
- // base route
- app.post("/:user", function (request, response) {
- response.send(request.params.user)
- });
- // base route
- app.put("/:user", function (request, response) {
- response.send(request.params.user)
- });
- // listen for requests, the process.env.PORT is needed because
- // we are using glitch, otherwise you could have written 80 or whatever
- var listener = app.listen(process.env.PORT, function () {
- console.log('Your app is listening on port ' + listener.address().port);
- });
- })
數(shù)據(jù)庫是按集合組織的,集合中包含文檔(基本上是 JSON 文件)。所以讓我們連接到 User 集合(我們***次訪問的時(shí)候會創(chuàng)建)。
- mongodb.MongoClient.connect(uri, function(err, db) {
- const collection = db.collection('users')
- // ...
- }
首先,我們先來操作一下 POST 路由。當(dāng)我們***次來添加用戶數(shù)據(jù)時(shí),將會用到該路由。然后我們要用 PUT 路由來更新數(shù)據(jù)。
- app.post("/:user", function (request, response) {
- // inserts a new document on the server
- collection.insertOne({ ...request.body, user : request.params.user }, function (err, r) {
- if (err){
- response.send("An error occured")
- }else{
- response.send("All well")
- }
- })
- });
collection.insertOne 方法給收集器添加了一個(gè)新的文檔。在這個(gè)例子中,每一個(gè)用戶都將會擁有他自己的文檔。
{ ...request.body, user : request.params.user } 利用 擴(kuò)展操作符 合并通過請求主體和用戶通過 URL 提供的數(shù)據(jù)。
被存儲在收集器其中的文檔便是運(yùn)行結(jié)果。
第二個(gè)參數(shù)是一個(gè)回調(diào),將操作結(jié)果簡單的通知給用戶。
從數(shù)據(jù)庫獲取數(shù)據(jù)
我們在服務(wù)器上存放了一些數(shù)據(jù),現(xiàn)在想從服務(wù)器上讀取這些數(shù)據(jù)。我們用 GET 方法來獲取。
- app.get("/:user", function (request, response) {
- collection.find({ user : request.params.user }).toArray(function (err, docs) {
- if (err){
- response.send("An error occured")
- }else{
- response.send(docs)
- }
- })
- });
此時(shí),***個(gè)參數(shù)是一個(gè)過濾器,用來告訴數(shù)據(jù)庫將用戶的屬性信息文檔只發(fā)給我們。
用戶信息以數(shù)組的形式保存在文檔中,因?yàn)閺睦碚撋现v不止一個(gè)文檔中保存著用戶的屬性信息。我們必須避免這種情況的發(fā)生。
文檔以數(shù)組的形式返回給用戶,因?yàn)槔碚撋峡梢杂卸鄠€(gè)具有該用戶屬性的文檔。我們必須確保這種情況不會發(fā)生。
更新數(shù)據(jù)庫數(shù)據(jù)
***而且很重要的是用 PUT 方法更新已存在的用戶信息。
- // base route
- app.put("/:user", function (request, response) {
- collection.updateOne({ user : request.params.user },
- {$set:{ ...request.body, user : request.params.user }},
- function (err, r) {
- if (err){
- response.send("An error occured")
- }else{
- response.send("All well")
- }
- })
- });
***個(gè)參數(shù)是一個(gè)過濾器,與 GET 方法的***個(gè)參數(shù)類似。
第二個(gè)參數(shù)是更新文檔請求—你能獲取更對信息從 這里 。在我們的例子中,我們告訴數(shù)據(jù)庫將用戶傳遞的數(shù)據(jù)與已存在的數(shù)據(jù)合并。
但是要小心,因?yàn)榍短讌?shù)將會被替換而不是合并。
***
對于數(shù)據(jù)庫和后臺編程來說這只是剛剛開始,但是這足以讓你開始個(gè)人項(xiàng)目。
之后我可能會寫一些關(guān)于身份驗(yàn)證的文章,在此之前,請不要在里邊存儲一些比較敏感的數(shù)據(jù)。
你可以修改這個(gè)完整的項(xiàng)目 在這 ,你將需要有一個(gè)自己的數(shù)據(jù)庫,如果你還不會創(chuàng)建,請回到 配置數(shù)據(jù)庫 部分。
如果你覺得這篇文章還不錯(cuò),請給它一些掌聲讓更多的人看到它。謝謝!