0%

nodeJS - Use express.js to create routes and import public data


將路由設計與應用的進入點分開

通常應用程式會有一個進入點(ex. app.js),藉此驅動其他的程式碼,如果將路由邏輯寫在同個檔案會使單一檔案變得很攏長。幸好express.js提供很方便的方法讓我們簡單使用自己所創造的路由

假設我們將管理員使用的路由寫在admin.js,把給使用者利用的路由寫在shop.js檔案

admin.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const express = require('express');

const router = express.Router();

router.use('/add-product', (req, res, next) => {
res.send('<form action="/product" method="POST"><input type="text" name="title"><button type="submit">Add Product</button></form>');
});

router.post('/product', (req, res, next) => {
console.log(req.body);
res.redirect('/');
});

module.exports = router;

shop.js

1
2
3
4
5
6
7
8
9
const express = require('express');

const router = express.Router();

router.get('/', (req, res, next) => {
res.send('<h1>Hello from Express!</h1>');
});

module.exports = router;

接著就可以在app.js引入這些routes
app.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const express = require('express');
const bodyParser = require('body-parser');

const adminRouter = require('./routes/admin');
const shopRouter = require('./routes/shop');

const app = express();

app.use(bodyParser.urlencoded({extended: false}));

app.use(shopRouter);
app.use(adminRouter);

app.listen(3000);

當路由不符合任何一個設計的路徑時回傳一個404 page

1
2
3
4
//如沒有特別設定路徑,預設路徑為'/',以'/'開頭的都會符合
app.use((req, res, next) => {
res.status(404).send("<h1>Page not found</h1>")
})

共同路徑與相同路徑

可以使用相同的路徑來處理不同類型的請求

1
2
3
4
5
6
7
8
router.get('/admin/add-product', (req, res, next) => {
res.send('<form action="/product" method="POST"><input type="text" name="title"><button type="submit">Add Product</button></form>');
});

router.post('/admin/add-product', (req, res, next) => {
console.log(req.body);
res.redirect('/');
});

如果路徑中有重複的部分,可以做以下更動
app.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const express = require('express');
const bodyParser = require('body-parser');

const adminRouter = require('./routes/admin');
const shopRouter = require('./routes/shop');

const app = express();

app.use(bodyParser.urlencoded({extended: false}));

app.use(shopRouter);
app.use('/admin', adminRouter);

app.listen(3000);

如此一來admin.js改成以下

1
2
3
4
5
6
7
8
9
10
// /admin/add-product => GET
router.get('/add-product', (req, res, next) => {
res.send('<form action="/admin/add-product" method="POST"><input type="text" name="title"><button type="submit">Add Product</button></form>');
});

// /admin/add-product => POST
router.post('/add-product', (req, res, next) => {
console.log(req.body);
res.redirect('/');
});

回傳html檔案及正確的檔案路徑

回傳完整的html檔案可以使用res.sendFile(‘路徑’),但這個路徑必須以作業系統的根部路為基礎的絕對路徑,且路徑的顯示方式可能因作業系統不同而不同,所以我們要使用另一個nodeJS core module,path

假設我們專案內檔案結構如下圖

admin.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const path = require('path');

const express = require('express');

const router = express.Router();
//__dirname為根據根目錄到該檔案的絕對路徑
router.get('/add-product', (req, res, next) => {
res.sendFile(path.join(__dirname, '../', 'views', 'add-product.html'))
});

router.post('/product', (req, res, next) => {
console.log(req.body);
res.redirect('/');
});

module.exports = router;

如果不想每次都要根據不同的檔案路徑來輸入不同的路徑字串,可以統一使用進入點當作絕對路徑,再輸入相對路徑
首先創個資料夾,裡面新增一個path.js檔案

path.js

1
2
3
const path = require('path');
//process為node的global變數,process.mainModule.filename會取得進入點(app.js)的絕對路徑
module.exports = path.dirname(process.mainModule.filename);

之後我們可以在每個需要routes路徑的檔案引入path.js檔,再根據整個專案作為根目錄輸入正確的相對路徑

admin.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const path = require('path');

const express = require('express');
const rootDir = require('../util/path');

const router = express.Router();

router.get('/add-product', (req, res, next) => {
res.sendFile(path.join(rootDir, 'views', 'add-product.html'))
});

router.post('/product', (req, res, next) => {
console.log(req.body);
res.redirect('/');
});

module.exports = router;

引入靜態資料

html檔案內直接撰寫CSS雖然可以運作,但是為了專案的整潔及方便管理,需要把CSS作為外部檔案再引入html內,直接使用路徑引入style將無法運作,所以我們需要express幫我們定義靜態檔案的資料夾位置

在app.js加入這一行
app.js

1
2
//express.static用來服務靜態檔案
app.use(express.static(path.join(__dirname, 'public')));

接著在html檔案內就可以引入放在public資料夾內的CSS檔案或圖片
<link rel= "stylesheet" href = "css/main.css">
往後引入靜態檔案時 (CSS, js, picture etc.),node就會先去尋找是否在我們設定的static路徑裡面,而這個路徑可以設定複數個。

參考資料