日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Node — 第六天(前后端分离)及(身份验证)

發布時間:2023/12/13 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Node — 第六天(前后端分离)及(身份验证) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

綜合應用服務端知識點搭建項目

下載安裝所需的第三方模塊

npm init -y npm i express cors mysql # express 用于搭建服務器 # cors 用于解決跨域 # mysql 用于操作數據庫# 后面用到什么,再下載

創建app.js

之前,我們開啟一個服務器,js文件名,一般都是 01-xxx.js 03-xxx.js。

對于正常的一個項目來說,用于開啟服務的js文件,一般都叫做 app.js

// 開啟服務 const express = require('express'); const app = express(); app.listen(3006, () => console.log('server running~'));

使用路由模塊精簡項目結構

使用路由模塊的原因(意義)

  • 試想,如果項目有100個路由(接口),全部放到app.js中,這樣的代碼不好維護,效率也比較低下
  • 所以需要按照路由(接口)功能的不同,分別使用小文件存放這些路由(接口),這些小文件就叫做路由模塊
    • 比如,登錄注冊相關的,全部放到 ./routers/login.js 中
    • 比如,文章處理相關的,全部放到 ./routers/article.js 中
    • 比如,書籍管理相關的,全部放到 ./routers/books.js 中

代碼如何實現

  • 路由文件中的代碼
    • 加載express
    • 創建路由對象
    • 將路由(接口)掛載到路由對象上
    • 導出路由對象
/*** 1. 加載express* 2. 創建路由對象* 3. 把路由掛載到路由對象上* 4. 導出路由對象*/const express = require('express'); const router = express.Router();// 下面是圖書管理相關的路由 router.get('/getbooks', (req, res) => {res.send('我是獲取書籍的接口'); });router.post('/addbook', (req, res) => {});router.get('/delbook', (req, res) => {});module.exports = router;
  • app.js 中的代碼
    • 加載路由模塊,并注冊成中間件。注冊的時候,可以統一加前綴
// 開啟服務 const express = require('express'); const app = express(); app.listen(3006, () => console.log('server running~'));// 加載路由模塊,并注冊成中間件 let books = require('./routers/books'); app.use('/api', books);

開啟服務(nodemon app.js) ,然后通過瀏覽器來測試一下你的接口是否能夠正常訪問

創建數據庫、數據表

數據庫,還可以使用昨天的 user 數據庫。

在里面創建一張數據表(books)

添加幾條模擬數據:

粗略的完成獲取書籍的接口

  • 目前:

    • 數據準備好了
    • 接口能夠正常訪問了
  • 下面要做的事情:

    • getbooks接口中,通過mysql模塊,查詢所有的書籍,并把結果響應給客戶端
    • 中間件解決跨域問題

getbooks接口

router.get('/getbooks', async (req, res) => {// 查詢數據庫user、數據表books里面的數據,把查詢的結果響應給客戶端const mysql = require('mysql'); // require加載一個模塊后,會緩存起來const conn = mysql.createConnection({host: 'localhost',user: 'root',password: '12345678',database: 'user' // 填寫數據庫名});conn.connect();conn.query('select * from books', (err, result) => {if (err) return console.log(err);res.json({status: 200,msg: '獲取成功',data: result});});conn.end(); });

應用級別的中間件解決跨域

  • 應用級別的中間件
    • 寫到app.js中的中間件
    • 該中間件會影響所有的路由
  • 路由級別的中間件
    • 寫到 路由文件中的中間件
    • 該中間件只會影響當前的路由文件

因為整個項目的全部路由都需要解決跨域問題,所以需要定義應用級別的中間件

所以,在app.js中,加入如下代碼:

// 配置中間件,解決跨域問題 app.use((req, res, next) => {res.set({'Access-Control-Allow-Origin': '*'});next(); });

封裝db.js

試想,后面還有很多路由中需要對數據庫進行操作,難道每次執行SQL語句,都要寫5個步驟(操作MySQL的5個步驟)嗎?

:肯定不是,那樣的話,代碼太多。代碼復用性太差了

解決辦法:封裝

具體做法

  • 創建 db.js
  • 里面封裝 使用mysql模塊的5個步驟
  • 導出函數
  • 其他路由中,需要加載(導入)db模塊,然后調用函數即可

db.js 中的代碼:

function db(sql, params, callback) {const mysql = require('mysql');const conn = mysql.createConnection({host: 'localhost',user: 'root',password: '12345678',database: 'user' // 填寫數據庫名});conn.connect();conn.query(sql, params, callback);conn.end(); }// 導出函數 module.exports = db;

getbooks接口中使用:

// 獲取書籍接口 router.get('/getbooks', async (req, res) => {// 查詢數據庫user、數據表books里面的數據,把查詢的結果響應給客戶端db('select * from books', null, (err, result) => {if (err) return console.log(err);res.json({status: 200,msg: '獲取成功',data: result});}); });

使用Promise

如果查詢書籍信息的時候,還要查詢總記錄數,怎么辦?

:嵌套查詢,嵌套的層數太多,就會形成回調地獄

解決辦法:使用Promise

具體做法

  • 在db.js中,加個一個封裝Promise的函數db2
  • db2中調用db函數,從而完成Promise的封裝
  • 導出db2
function db(sql, params, callback) {const mysql = require('mysql');const conn = mysql.createConnection({host: 'localhost',user: 'root',password: '12345678',database: 'user' // 填寫數據庫名});conn.connect();conn.query(sql, params, callback);conn.end(); }function db2 (sql, params) {return new Promise((resolve, reject) => {// 這里寫異步代碼db(sql, params, (err, result) => {err ? reject(err) : resolve(result);});}); }// 導出函數 module.exports = db2;

優化上述兩個函數

function db (sql, params = null) {const mysql = require('mysql'); // require加載一個模塊后,會緩存起來const conn = mysql.createConnection({host: 'localhost',user: 'root',password: '12345678',database: 'user' // 填寫數據庫名});return new Promise((resolve, reject) => {// 這里寫異步代碼conn.connect();conn.query(sql, params, (err, result) => {err ? reject(err) : resolve(result);});conn.end();}); }// 導出函數 module.exports = db;

完整的圖示

Web 開發模式

目前主流的 Web 開發模式有兩種,分別是:

  • 基于服務端渲染的傳統 Web 開發模式
  • 基于前后端分離的新型 Web 開發模式
  • 服務端渲染的開發模式

    特點:

    • 所有的web資源由同一個服務器統一管理(前后端代碼必須放到一起)

    • 頁面和頁面中使用的數據,由服務器組裝,最后將完整的HTML頁面響應給客戶端

    代碼:

    // 用于開啟服務const fs = require('fs'); const express = require('express'); const app = express(); app.listen(3000, () => console.log('啟動了'));// 顯示首頁的接口 app.get('/index.html', (req, res) => {// res.send('1111')fs.readFile('./public/index.html', 'utf-8', (err, data) => {if (err) return console.log(err);data = data.replace('{{title}}', '憫農');data = data.replace('{{content}}', '鋤禾日當午,汗滴禾下土');res.send(data);}); });

    真實的服務端渲染模式和前后端分離的模式,難度上差不多。

    優點:

    • **前端耗時少。**因為服務器端負責動態生成 HTML 內容,瀏覽器只需要直接渲染頁面即可。尤其是移動端,更省電。
    • 有利于SEO。因為服務器端響應的是完整的 HTML 頁面內容,所以爬蟲更容易爬取獲得信息,更有利于 SEO(搜索引擎)。

    缺點:

    • **占用服務器端資源。**即服務器端完成 HTML 頁面內容的拼接,如果請求較多,會對服務器造成一定的訪問壓力。

    • 不利于前后端分離,開發效率低。使用服務器端渲染,則無法進行分工合作,尤其對于前端復雜度高的項目,不利于 項目高效開發。

    前后端分離的開發模式

    特點:

    • 依賴于Ajax技術
    • 后端不提供完整的 HTML 頁面內容,而 是提供一些 API 接口
    • 前端通過 Ajax 調用后端提供的 API 接口,拿到 json 數據 之后再在前端進行 HTML 頁面的拼接,最終展示在瀏覽器上。

    簡而言之,前后端分離的 Web 開發模式,就是后端只負責提供 API 接口,前端使用 Ajax 調用接口的開發模式。

    優點:

    • **開發體驗好。**前端專注于 UI 頁面的開發,后端專注于api 的開發,且前端有更多的選擇性。
    • **用戶體驗好。**Ajax 技術的廣泛應用,極大的提高了用戶的體驗,可以輕松實現頁面的局部刷新。
    • **減輕了服務器端的渲染壓力。**因為頁面最終是在每個用戶的瀏覽器中生成的。

    缺點:

    • **不利于SEO。**因為完整的 HTML 頁面需要在客戶端動態拼接完成,所以爬蟲對無法爬取頁面的有效信息。(解決方 案:利用 Vue、React 等前端框架的 SSR (server side render)技術能夠很好的解決 SEO 問題!)

    如何選擇 Web 開發模式

    不談業務場景而盲目選擇使用何種開發模式都是耍流氓。

    • 比如企業級網站(公司的網站),主要功能是展示而沒有復雜的交互,并且需要良好的 SEO,則這時我們就需要使用服務器端渲染;

    • 而類似后臺管理頁面,交互性比較強,不需要 SEO 的考慮,那么就可以使用前后端分離的開發模式。

    • 另外,具體使用何種開發模式并不是絕對的,為了同時兼顧首頁的渲染速度前后端分離的開發效率,一些網站采用了 首屏服務器端渲染,即對于用戶最開始打開的那個頁面采用的是服務器端渲染,而其他的頁面采用前后端分離開發模式。

    身份認證機制

    對于服務端渲染和前后端分離這兩種開發模式來說,分別有著不同的身份認證方案:

    • 服務端渲染推薦使用 Session 認證機制(Session也會用到Cookie)
    • 前后端分離推薦使用 JWT 認證機制

    Cookie

    原理

    實現身份認證

    • 搭建基礎的服務器
      • 下載安裝第三方模塊 express 和 cookie-parser

      • 創建app.js

      • 加載所需模塊

        • const express = require('express');
        • const cookieParser = require('cookie-parser');
    • 中間件配置 cookie-parser
      • app.use(cookieParser())
    • 實現三個路由
      • /login.html (里面直接響應login.html頁面)
      • /api/login
      • /index.html (里面直接響應index.html頁面)
    • 創建存放index頁面的public文件夾
      • 創建index.html
      • 創建login.html
    • 完成登錄接口
      • 如果登錄成功,設置cookie。res.cookie('key', 'value', 配置項);
      • 跳轉到 /index.html 路由
    • /index.html 路由中,根據cookie判斷是否登錄,從而完成身份認證

    詳見代碼

    const express = require('express'); const cookieParser = require('cookie-parser'); const path = require('path');const app = express(); app.listen(3000, () => console.log('啟動了'));// 接收POST請求體 app.use(express.urlencoded({extended: false})); // 配置cookie-parser app.use(cookieParser());// 準備三個路由// 用于顯示登錄頁面 app.get('/login.html', (req, res) => {// sendFile方法,可以讀取文件,并將讀取的結果響應給客戶端// 要求,參數必須是一個絕對路徑res.sendFile(path.join(__dirname, 'public', 'login.html')); });// 用于完成登錄驗證的(判斷賬號密碼是否正確的接口) app.post('/api/login', (req, res) => {// console.log(req.body);// 約定,假設賬號是 admin、密碼是123if (req.body.username === 'admin' && req.body.password === '123') {// 登錄成功,跳轉到index.html// 設置cookie// res.cookie('key', 'value', '選項');// res.cookie('isLogin', 1); // 沒有填選項,默認cookie有效期是會話結束res.cookie('isLogin', 1, {maxAge: 2*60*1000});res.send('<script>alert("登錄成功"); location.href="/index.html";</script>');} else {// 登錄失敗} });// 顯示index.html頁面的 app.get('/index.html', (req, res) => {// 獲取cookie// console.log(req.cookies);if (req.cookies.isLogin && req.cookies.isLogin === '1') {res.sendFile(path.join(__dirname, 'public', 'index.html'));} else {// 沒有登錄res.send('<script>alert("請先登錄"); location.href="/login.html";</script>');} });

    優缺點

    • 優點
      • 體積小
      • 客戶端存放,不占用服務器空間
      • 瀏覽器會自動攜帶,不需要寫額外的代碼,比較方便
    • 缺點
      • 客戶端保存,安全性較低。但可以存放加密的字符串來解決
      • 可以實現跨域,但是難度大,難理解,代碼難度高
      • 不適合前后端分離式的開發

    適用場景

    • 傳統的服務器渲染模式
    • 存儲安全性較低的數據,比如視頻播放位置等

    Session

    原理

    實現身份認證

    • 搭建基礎的服務器

      • 下載安裝第三方模塊 express 和 express-session

      • 創建app.js

      • 加載所需模塊

        • const express = require('express');
        • const session = require('express-session');
    • 中間件配置 session

      app.use(session({secret: 'adfasdf', // 這個隨便寫saveUninitialized: false,resave: false }))
    • 實現三個路由

      • /login.html (里面直接響應login.html頁面)
      • /api/login
      • /index.html (里面直接響應index.html頁面)
    • 創建存放index頁面的public文件夾

      • 創建index.html
      • 創建login.html
    • 完成登錄接口

      • 如果登錄成功,使用session記錄用戶信息。

        req.session.isLogin = 1; req.session.username = req.body.username;
      • 跳轉到 /index.html 路由

    • /index.html 路由中,根據session判斷是否登錄,從而完成身份認證

    詳見代碼

    const express = require('express'); const session = require('express-session'); const path = require('path');const app = express(); app.listen(3000, () => console.log('啟動了'));// 接收POST請求體 app.use(express.urlencoded({extended: false})); // 配置session app.use(session({secret: 'asdf23sfsd23',// 下面兩項,設置成true或者false,都可以。使用內存存儲session的時候,下面兩項沒作用saveUninitialized: false,resave: false }));// 準備三個路由// 用于顯示登錄頁面 app.get('/login.html', (req, res) => {// sendFile方法,可以讀取文件,并將讀取的結果響應給客戶端// 要求,參數必須是一個絕對路徑res.sendFile(path.join(__dirname, 'public', 'login.html')); });// 用于完成登錄驗證的(判斷賬號密碼是否正確的接口) app.post('/api/login', (req, res) => {// console.log(req.body);// 假設賬號任意,密碼必須是123if (req.body.password === '123') {// 假設登錄成功// req.session.xxxx = 'yyyy'req.session.isLogin = 1; /*<p>歡迎你:{{username}}</p> */req.session.username = req.body.username;// 做出響應res.send('<script>alert("登錄成功"); location.href="/index.html";</script>');} });// 顯示index.html頁面的 app.get('/index.html', (req, res) => {// 獲取session req.sessionif (req.session.isLogin && req.session.isLogin == 1) {const fs = require('fs');fs.readFile('./public/index.html', 'utf-8', (err, data) => {if (err) return console.log(err);// 更換用戶名data = data.replace('{{username}}', req.session.username);res.send(data);});} else {res.send('<script>alert("請登錄"); location.href="/login.html";</script>');}});

    優缺點

    • 優點
      • 服務端存放,安全性較高
      • 瀏覽器會自動攜帶cookie,不需要寫額外的代碼,比較方便
      • 適合服務器端渲染模式
    • 缺點
      • 會占用服務器端空間
      • session實現離不開cookie,如果瀏覽器禁用cookie,session不好實現
      • 不適合前后端分離式的開發

    適用場景

    • 傳統的服務器渲染模式
    • 安全性要求較高的數據可以使用session存放,比如用戶私密信息、驗證碼等

    總結

    以上是生活随笔為你收集整理的Node — 第六天(前后端分离)及(身份验证)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。