[學習筆記] React + Express + MySQL 實作簡易登入及註冊系統

最後更新於 2022 年 4 月 8 日

在這個簡單的實例中,我們會使用 Express(針對 Node.js 的 Web 應用框架) 來處理後端,再將 React 應用與後端做連結執行SQL語句達到登入及註冊的效果。

僅僅只是實現登入註冊系統的無限種方法之一,所有寫法為本人實作可行,並非最優解,若有不足之處或者更好的處理方式歡迎回復一起交流。

本篇文章著重於後端路由配置以及與MySQL資料庫的連結,前端部分會盡量省略。本人是後端小白!本篇為學習筆記,僅供參考,寫法很次,輕噴。

效果演示

頁面 UI 製作

首先把 React 應用的 登入註冊UI 設計好,個人直接使用 Material UI 提供的模板

我的 React 應用 port 為 3000

套件版本

前後端使用到的套件和框架的版本:

  • React:17.0.2
  • Express:4.17.2
  • React-router-dom:6.2.1
  • axios:0.24.0
  • express-validator:6.14.0
  • bcrypt:5.0.1
  • jsonwebtoken:8.5.1

後端架設

因為我們需要使用 express 作為後台,所以需要先安裝 express

npm install express --save

在 React 應用 project 目錄底下新增 server 資料夾,並在 server 資料夾中新增 app.js

const express = require('express');
const app = express();
const port = 7000; // your server port

app.get('/', (req, res) => {
  res.send('Hello World!');
});

app.listen(port, () => {
  console.log(`RUN http://localhost:${port}`)
});

輸入指令啟動 app 看看:

cd server
node app.js

若正常無誤則控制台會顯示 RUN http://localhost:7000,打開瀏覽器輸入 http://localhost:7000 回車即能看到 Hello World! 這樣就建立了一個很簡易的 node server。

串接 MySQL

安裝 MySQL tool:

npm install mysql --save

打開 XAMPP,啟用 MySQLApache 服務,接著打開 phpMyAdmin

http://localhost/phpmyadmin

新增一個資料庫 demoaccount 資料表,欄位按照用戶資料設計,並嘗試新增一筆資料。

account [學習筆記] React + Express + MySQL 實作簡易登入及註冊系統

接著我們在 server 底下新增 config/db.js 我們將與資料庫連接的內容添加進去:

const mysql = require("mysql");

// connect MySQL
var connection = mysql.createConnection({
    host: "localhost",
    user: "root",
    password: "",
    database: "demo",
});

module.exports = connection;

回到 server/app.js,引入 db.js,現在完整的 app.js 內容如下:

const express = require("express");
const db = require('./config/db');
const app = express();
const port = 7000;

app.use(express.json());
app.listen(port, () => {
  console.log(`RUN http://localhost:${port}`);
});

接著我們試著在 app.js 中執行一個 select 語句看看能否抓到資料庫裡面的資料:

db.query('select * from account', function(err, rows) {
  if (err) throw err;
  console.log('Response: ', rows);
});

再次執行 node app.js 後就能在控制台看到 account 資料表中的所有資料了。

Response:  [ RowDataPacket { id: 1, username: 'admin', password: 'admin' } ]

獲取請求中的參數

在接下來的實作中,我們會需要獲取請求中的參數來做後續的處理,所以先用一小篇幅介紹一下三種常見獲取請求參數方式:

  1. req.body
  2. req.query
  3. req.params

req.body

通常用來解析 POST 請求中的參數,比如:

// 前端請求
axios.post("http://localhost:7000/signin", {
  username: "admin",
  password: "123456"
});

// 後端獲取參數
app.post("signin", function(req, res) {
  const { username, password } = req.body;
});

req.query

多適用於 GET 請求,用於解析 GET 請求中的參數,比如:

// 前端請求
axios.get("http://localhost:7000/user", { params: { id: 1 } });

// 後端獲取參數
app.get("user", function(req, res) {
  const { id } = req.query;
});

請求的路徑為:http://localhost:7000/user?id=1

req.params

通常用在 GET 請求中,比如:

// 前端請求
axios.get("http://localhost:7000/user/1");

// 後端獲取參數
app.get("user/:id", function(req, res) {
  const { id } = req.params;
});

實作登入功能

配置登入路由

完成以上的準備工作後,我們需要來配置登入及註冊的路由,然後執行相應的SQL語句達到登入與註冊的功能。

post 的參數我們需要使用 req.body 來接收,因此我們會需要先定義帳號及密碼變數,然後將傳過來的值賦予給這兩個變數:

app.post("/signin", function(req, res) {
  const { username, password } = req.body;
});

接著就是執行 select 語句,如果查詢不到結果會回傳 ACCOUNT_NOT_EXIST,如果沒有則用回傳 LOGIN_SUCCESSFULLY

app.post("/signin", function(req, res) {
  const { username, password } = req.body;
  db.query(
    `SELECT * FROM account WHERE username='${username}' AND password='${password}'`,
    function(err, rows, fields) {
      if (rows.length === 0) {
        return res.send({ error: 'ACCOUNT_NOT_EXIST' });
      };
      return res.send({ message: 'LOGIN_SUCCESSFULLY' });
    }
  );
});

前端發送請求

後端路由配置完成後,我們就需要回到前端完成登入的方法,這個例子中我們會藉由 axios 來創建請求,因此需要先安裝 axios:

npm install axios

接著使用 axios.post() 來實作 login 方法:

const [username, setUsername] = useState("");
const [password, setPassword] = useState("");

const login = (e) => {
    if (username !== "" && password !== "") {
      axios
        .post("http://localhost:7000/signin", {
          username: username,
          password: password,
        })
        .then((res) => {
          alert("登入成功!");
          navigate("/home");
        })
        .catch((e) => {
          if (e.response.error) {
            alert("帳號或密碼錯誤!");
          }
        });
    } else if (username === "") {
      alert("請輸入帳號!");
    } else {
      alert("請輸入密碼!");
    }
  };

解決跨域問題

此刻我們的登入功能應該是還無法正常操作的,因為當我們跨來源請求且 server 沒有正確設定時就會因違反 CORS 而失敗。我們的 server port 為 7000,應用 port 為 3000,構成了跨域請求,完整的報錯內容如下:

Access to fetch at 'http://localhost:7000/signin' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
cors [學習筆記] React + Express + MySQL 實作簡易登入及註冊系統

這邊我們用 CORS (CORS 是一個 node.js 包,用於提供Connect / Express中間件)來解決,所以需要先安裝:

npm install cors

然後在 server/app.js 中使用中間件來解決跨域問題:

const cors = require('cors');
app.use(cors());

如此一來登入功能便能正常使用。

實作註冊功能

既然完成了登入功能,那麼註冊功能也是一樣的套路。

配置註冊路由

與登入不同之處在於,註冊功能使用的是 insert 語句,而我們用戶資料表的 idAUTO_INCREMENT 所以無須插入:

app.post("/signup", function(req, res) {
  const { username, password } = req.body;
  connection.query(
    `INSERT INTO account(username, password) VALUES ('${username}', '${password}')`,
    function(err, rows, fields) {
      if (err) throw err;
      return res.send({ message: "REGISTER_SUCCESSFULLY" });
    }
  );
});

前端發送請求

與登入部分相差無幾,就不多做解釋:

const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [rePassword, setRePassword] = useState("");

const submit = (e) => {
    if (username !== "" && password !== "" && rePassword !== "") {
      axios
        .post("http://localhost:7000/signup", {
          username,
          password,
          rePassword
        })
        .then((res) => {
          alert("註冊成功!");
          navigate("/signin");
        })
        .catch((e) => {
          alert("註冊失敗!", e);
        });
    } else if (username === "") {
      alert("請輸入帳號!");
    } else if (password === "") {
      alert("請輸入密碼!");
    } else if (password !== rePassword) {
      alert("兩次密碼輸入不一致!");
    }
};

檢驗帳號是否已經存在

username 設為 unique key(獨一鍵):

unique [學習筆記] React + Express + MySQL 實作簡易登入及註冊系統

如此一來,若註冊時資料表中已經存在相同的 username 會回傳 ER_DUP_ENTRY,我們只需要處理接收到 ER_DUP_ENTRY 錯誤的結果:

app.post("/signup", function(req, res) {
  const { username, password, rePassword } = req.body;
  db.query(
    `INSERT INTO account(username, password) VALUES ('${username}', '${password}')`,
    function(err, rows, fields) {
      if (err.code == "ER_DUP_ENTRY") {
        return res.send({ error: "ACCOUNT_ALREADY_EXISTS" });
      };
      return res.send({ message: "REGISTER_SUCCESSFULLY" });
    }
  );
});

同樣記得修改前端的註冊方法:

const submit = (e) => {
    if (username !== "" && password !== "" && rePassword !== "" && password === rePassword) {
      axios
        .post("http://localhost:8000/signup", {
          account,
          password,
          rePassword
        })
        .then((res) => {
          alert("註冊成功!", username);
          navigate("/signin");
        })
        .catch((e) => {
          if (e.response.error) {
            alert("註冊失敗!此帳號已存在,請嘗試新的帳號!");
          }
        });
    } else if (username === "") {
      alert("請輸入帳號!");
    } else if (password === "") {
      alert("請輸入密碼!");
    } else if (password !== rePassword) {
      alert("兩次密碼輸入不一致!");
    }
  };

後端表單驗證

實際上,正式應用中不會純前端做表單驗證,後端也需要對用戶傳送過來的資料做驗證,因此我個人是會安裝 express-validator 這個套件來驗證資料是否符合需求。

https://express-validator.github.io/docs/

express-validator

我們可以使用 express-validator 提供的 body, query 和 params 來驗證傳過來的值是否符合我們的需求,body 對應的是 req.body , query 是 req.query 而 params 則是 req.params,或者也可以直接使用 check ,包含以上說的所有。

因為註冊和登入使用的是 POST 方式,所以傳過來的值通常會是 req.body,因此我們使用 body 就可以,下面舉一個例子:

const { body, validationResult } = require("express-validator");

body('email').isEmail(), // 檢查 req.body.email 是否為 email 格式
body('password').trim().isLength({ min: 8 }), // 檢查 req.body.password 去除空白後長度是否為 8 (含)個字元以上

實作註冊表單驗證

post /signup 的第二個參數改為表單驗證,第三個參數為表單驗證通過後調用的方法:

  • .withMessage() 方法用於驗證錯誤後回傳錯誤訊息
  • .custom() 自定義驗證內容
app.post(
  "/signup",
  [
    body("username")
      .trim()
      .isLength({ min: 6 })
      .withMessage("USERNAME_INVALID"), // 帳號必填, 且至少 6 個字元以上
    body("password")
      .trim()
      .isLength({ min: 8 })
      .withMessage("PASSWORD_INVALID"), // 密碼必填, 且至少 8 個字元以上
    body("rePassword")
      .trim()
      .custom((value, { req }) => {
        if (value !== req.body.password) {
          throw new Error("PASSWORD_DOES_NOT_MATCH"); // 兩次輸入的密碼不相同
        }
        return true;
      }),
  ],
  authController // 調用該方法
);

authController 一樣接收兩個函數 req 及 res,validationResults() 用於驗證結果,會返回一個 Result object,若驗證內容有不符合需求的,validationResults.errors 會回傳錯誤內容,因此我們可以藉由檢查 validationResults.errors 是否長度不為零來判斷是否有不符合的內容傳過來:

const authController = (req, res) => {
  const { username, password } = req.body;
  const validationResults = validationResult(req); // 驗證傳過來的內容是否符合我們的要求

  if (validationResults.errors?.length > 0) {
    return res.status(422).send({ errors: validationResults.errors }); // 若有錯誤則回傳錯誤內容
  }

  db.query(
    `INSERT INTO account(username, password) VALUES ('${username}', '${password}')`,
    function(err, rows, fields) {
      if (err.code == "ER_DUP_ENTRY") {
        return res.send({ error: "ACCOUNT_ALREADY_EXISTS" });
      };
      return res.send({ message: "REGISTER_SUCCESSFULLY" });
    }
  );
};

至於登入需不需要進行表單驗證就看個人需求了,都是差不多的寫法。

對密碼進行加密

目前,我們註冊帳戶時密碼是直接存入資料庫的,但為了帳號安全,我們通常會希望存入的是加密過後的內容。

而對密碼加密我會使用 bcrypt 這個套件,因此我們需要先進行安裝:

npm i bcrypt

然後在 server/app.js 中引入 bcrypt:

const bcrypt = require("bcrypt");

我們需要使用 bcrypt 提供的 hashSync 函數來對傳入的密碼進行加密:

  • 這邊的 10 指的是 saltRounds,saltRounds 值越高,散列算法需花費的時間就越多,我們使用預設的 10 就可以。
req.body.password = bcrypt.hashSync(req.body.password, 10);

現在來修改 authController 的部分:

const authController = (req, res) => {
  const { username, password } = req.body;
  const validationResults = validationResult(req);

  if (validationResults.errors?.length > 0) {
    return res.status(422).send({ errors: validationResults.errors });
  }

  password = bcrypt.hashSync(password, 10); // 將使用者輸入的密碼進行加密

  db.query(
    `INSERT INTO account(username, password) VALUES ('${username}', '${password}')`, // 保存加密後的密碼至資料庫
    function(err, rows, fields) {
      if (err.code == "ER_DUP_ENTRY") {
        return res.send({ error: "ACCOUNT_ALREADY_EXISTS" });
      };
      return res.send({ message: "REGISTER_SUCCESSFULLY" });
    }
  );
};

此時註冊可以看見存入資料庫的密碼已經經過加密,這串加密後的密碼長度為 60

  • 請注意資料表中 password 的長度不能小於 60 以下的長度,否則後續的密碼比對會失敗。
密碼加密 [學習筆記] React + Express + MySQL 實作簡易登入及註冊系統
密碼加密2 [學習筆記] React + Express + MySQL 實作簡易登入及註冊系統

登入的部分也要將傳入的密碼進行加密,並使用 bcrypt 提供的 compareSync 函數和資料庫儲存的密碼進行比對,若相同代表密碼正確,才允許使用者登入:

app.post("/signin", function(req, res) {
  const { username, password } = req.body;

  db.query(
    `SELECT * FROM account WHERE username='${username}'`,
    function(err, rows, fields) {
      if (err) throw err;
      if (rows.length === 0) {
        return res.send({ error: "ACCOUNT_NOT_EXIST" });
      };
      
      const psRes = bcrypt.compareSync(password, result[0].password); // 將使用者輸入的密碼和存在資料庫的密碼進行比較

      if (!psRes) { // 比對失敗
        res.send({ error: "WRONG_PASSWORD" });
      }
      return res.send({ message: "LOGIN_SUCCESSFULLY" });
    }
  );
});

登入後產生 token

帳號的權限驗證幾乎可以說是整個應用最重要的部分之一,因此我們會需要在登入的時候給予使用者一個 token,此 token 可以獲取使用者的登入狀態,有了這個 token 就可以使用應用中的功能,若 token 到期或者不存在,則使用者無法使用此應用中的功能。

JWT 的全名為 JSON Web Token,是一種基於 JSON 的開放標準,用於在雙方之間安全地將訊息作為 JSON 物件傳輸,並且這個訊息是經過數位簽章,所以能夠被驗證及信任。可以使用 密碼(經過 HMAC 演算法) 或用一對 公鑰/私鑰(經過 RSA 或 ECDSA 演算法) 來對 JWT 進行簽章。

關於 Token 建議可以再閱讀一下這兩篇文章:

身分驗證(Token & Session) 的部分我有發了一篇筆記,更詳細的針對身分驗證的部分做了說明,有需要可以參考一下:Express學習筆記(5) – 身分驗證 Session & JWT Token

後端產生 token

安裝 JWT:

npm i jsonwebtoken

server/app.js 中引入 JWT:

const jwt = require("jsonwebtoken");

jwt 加密方法使用方式為:

jwt.sign(payload, secretOrPrivateKey, [options, callback]);

現在我們在 server/config 底下新增 token.js,這個 jwtKey 是我們要加密的內容:

module.exports = {
    jwtKey: 'pluto'
};
token [學習筆記] React + Express + MySQL 實作簡易登入及註冊系統

回到 app.js 中在 signin 底下調用 jwt.sign 方法,傳入帳號,並傳入加密的 key 和 token 過期時間:

  • expiresIn 為 token 時效,數值被解釋為秒數。如果您使用字符串,請確保提供時間單位(天、小時等),否則默認使用毫秒單位("120"等於"120ms"),詳細請參考官方說明
const jwt = require("jsonwebtoken");
const config = require("./config/token");

// ...

app.post("/signin", function(req, res) {
  const { username, password } = req.body;

  db.query(
    `SELECT * FROM account WHERE username='${username}'`,
    function(err, rows, fields) {

      if (rows.length === 0) {
        return res.send({ error: "ACCOUNT_NOT_EXIST" });
      };

      const psRes = bcrypt.compareSync(password, rows[0].password);

      if (!psRes) {
        res.send({ error: "WRONG_PASSWORD" });
      }
      const payload = {
        id: result[0].id,
        username: result[0].username,
      };
      const token = jwt.sign(payload, config.jwtKey, { expiresIn: '24h' }); // 根據 username 生成 token
      // 將 token 回傳
      return res.send({
        message: "LOGIN_SUCCESSFULLY",
        token
      });
    }
  );
});

現在我們來登入測試一下是否會產生 token,可以看到登入後控制台輸出了一串內容,這是 username 經由我們所給的 jwtKey 進行加密後的內容,我們將它作為登入的 token

獲取登入token 1 [學習筆記] React + Express + MySQL 實作簡易登入及註冊系統

每次登入都會重新產生 token,若是不重新登入則 token 可以維持 24 個小時(看你是設多久),我們就可以藉由 token 是否存在及是否過期來限制使用者能夠進行哪些活動。

前端保存 token

現在知道後端會在登入後回傳 token,所以我們可以在前端將登入後回傳的 token 保存到本地和上下文中。

目前大部分應用(以 React 來說)中都是將 Token 透過 localStorage Context 保存,當然也有其他種方式,你可以根據個人需求使用不同方式保存,但這裡就只用常見的方式舉例。

在 React project 根目錄中新建 context.js

import { createContext } from "react";

export default createContext({ token: undefined });

App.js 的 App function 中聲明 token 並且將它加入上下文:

import { useState, useContext } from "react";
import Context from "./context";

function App() {
  const [token, setToken] = useState(localStorage.getItem("token"));
  
  return (
    <Context.Provider
      value={{
        token,
        setToken,
      }}
    >
      // ...
    </Context>
}

回到 Login.js 從上下文中解構賦值 setToken,將登入後回傳的 token 存至 context 和本地,並且記得將 axios 請求頭帶上 token:

const { setToken } = useContext(context);
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");

const login = (e) => {
    if (username !== "" && password !== "") {
      axios
        .post("http://localhost:7000/signin", {
          username: username,
          password: password,
        })
        .then((res) => {
          axios.defaults.headers.common["authorization"] = res.data.token; // axios 請求頭帶上 token
          setToken(res.data.token); // 保存至 context
          localStorage("token", res.data.token); // 保存到本地
          navigate("/home");
        })
        .catch((e) => {
          if (e.response.error) {
            alert("帳號或密碼錯誤!");
          }
        });
    } else if (username === "") {
      alert("請輸入帳號!");
    } else {
      alert("請輸入密碼!");
    }
  };

驗證 token 是否存在

後端

後端部分所有需要有 token 才能請求的方法需要先經由驗證才能請求,因此我們需要新建一個 middleware.js 用於驗證使用者請求時是否帶有 token:

  • jwt.verify 用於驗證 token 是否包含我們所設定的 key,用法:jwt.verify(token, secretOrPublicKey, [options, callback])
const jwt = require("jsonwebtoken");
const config = require("./config/token");

const authentication = (req, res, next) => {
  let token;

  try {
    token = req.headers["authorization"]; // 從請求 headers 中找 token
  } catch (e) {
    token = "";
  }

  jwt.verify(token, config.jwtKey, function (err, decoded) {
    if (err) {
      return res.status(401).json({ message: "Unauthorized" }); // 失敗時回傳 Unauthorized 錯誤訊息
    } else {
      next(); // 成功則繼續進行請求
    }
  });
};

module.exports = authentication;

app.js 中加上下方程式碼進行 token 驗證,所有在這行底下的請求都會需要 token 才能繼續進行,若有不需要驗證的方法請放在此句之前:

app.use(authenticationMiddleware);

前端

前端目前是登入後會產生 token,在實際應用中,一個網站通常會有一些鑒權路由需要使用者登入後才能訪問及操作,而要做到私人路由最常見的方式就是藉由檢查是否有 token 才能繼續訪問。

App.js 中加上判斷,若本地存有 token 則將所有請求頭帶上 token,並且當 token 有變化時,會 call 隨便一個需要 token 才能請求的 API 來判斷 token 是否有效,若有效才能訪問私人路由:

import { useEffect, useState, useContext } from "react";
import { Routes, Route, useNavigate, BrowserRouter } from "react-router-dom";
import axios from "axios";
import { getUserList } from "./api";
import Context from "./context";

const PrivateRoute = ({ component, auth }) => {
  const { token } = useContext(Context);

  if (auth || token) {
    return component;
  } else {
    return <Redirect to="/login" />;
  }
};

const Redirect = ({ to }) => {
  let navigate = useNavigate();
  useEffect(() => {
    navigate(to, true);
  }, []);
  return null;
};

function App() {
  const [token, setToken] = useState(localStorage.getItem("token"));
  const [auth, setAuth] = useState();

  useEffect(() => {
    const token = localStorage.getItem("token");
    if (token) {
      axios.defaults.headers.common["authorization"] = token;
      setToken(token);
    } else {
      setToken(null);
    }
  }, []);

  useEffect(() => {
    getUserList()
      .then(() => setAuth(true))
      .catch(() => setAuth(false));
  }, [token]);

  return (
    <Context.Provider
      value={{
        token,
        setToken,
      }}
    >
      <div style={{ width: "100%", height: "100%" }}>
        <BrowserRouter>
          <Routes>
            <Route path="login" element={<Login />} />
            <Route path="register" element={<Register />} />
            <Route
              path="/"
              element={<PrivateRoute component={<Home />} auth={auth} />}
            />
          </Routes>
        </BrowserRouter>
      </div>
    </Context.Provider>
  );
}

雖然到目前為止註冊、登入及驗證 token 的流程應該是可以順利進行了,但當我登入後刷新頁面會發現路由又重定向到了登入頁面,即使本地存有 token 也一樣,在網路上找了很多相關資料終於找到了解決辦法。

我們可以藉由動態從本地抓取最新 token 添加到 axios 請求的 headers 中來解決這個問題。

在 React project 中添加 api.js ,創建 axios 實例,將所有關於 axios 請求的路由寫成 function 導出:

import axios from "axios";
const baseURL = "http://localhost:7000/";

// 從 localStorage 中獲取 token
function getLocalToken() {
  const token = window.localStorage.getItem("token");
  return token;
}

// 創建一個 axios 實例
export const request = axios.create({
  baseURL,
  headers: {
    authorization: getLocalToken(), // headers 塞 token
  },
});

// user
export const getUserList = (params) => request.get("/user", { params });
export const postUserLogin = (data) => request.post("/login", data);
export const postUserSignup = (data) => request.post("/signup", data);
....

其他頁面中原先有使用到 axios 的部分也需要修改,舉個例子,可以將登入方法改為:

import { request, postUserLogin } from "../../api";

// ...

const login = (data) => {
    if (data) {
      postUserLogin({
        username: data.username,
        password: data.password,
      })
        .then((res) => {
          request.defaults.headers.common["authorization"] = res.data.token;
          localStorage.setItem("token", res.data.token);
          setToken(res.data.token);
          navigate("/home");
        })
        .catch((e) => {
          if (e.response?.data.error) {
            // 錯誤處理
          }
        });
    } else {
      // 輸入內容錯誤處理
    }
  };

其他部分也一樣,就不再貼程式碼了。

捕獲解析 Token 失敗後產生的錯誤

當解析 Token 時,如果前端發送過來的 Token 過期或不合法,會產生一個解析失敗的錯誤,影響整個項目的運行。

我們可以通過 Express 的錯誤中介軟體捕獲這個錯誤並進行相關的處理:

//....

app.use((err, req, res, next) => {
	if (err.name === "UnauthorizedError") {
		return res.status(401).send({ message: "WRONG_TOKEN" });
	}
	res.send({ status: 500, message: "SERVER_ERROR" });
});

記得要將這個錯誤中介軟體放在 app.js 最底下,當 API 呼叫失敗時就會執行這個中介軟體,將錯誤訊息回傳。

補充

因為我是後端小白,如果是有後端經驗的朋友看到我的程式碼能很明顯的看出… 這些程式碼僅僅只是用最容易理解的方式呈現,後續還有很多優化的空間,比如 sql 語句的封裝整合、前端API的整合以及錯誤處理的方式…等。這篇文章我也會隨著我之後的學習慢慢優化及完善,如果需要比較系統學習的朋友建議還是看專業的教學文章。

延伸閱讀:

0 0 評分數
Article Rating
訂閱
通知
guest

0 Comments
在線反饋
查看所有評論