跳至主要内容

[Express] Express 起步走 Getting Started

Express

設定靜態路徑:express.static

// app.js
app.use('/upload', express.static(`${__dirname}/upload`));

Response

res.locals

僅作用於該 request - response 的物件,因此只能在該 request-response 所轉譯的頁面取得,除此之外它和 app.locals 是一樣的。適合用在使用者資訊的設定、驗證等。

// controller
app.use(function (req, res, next) {
res.locals.user = req.user;
res.locals.authenticated = !req.user.anonymous;
next();
});

可以直接在 View 的地方取得 userauthenticated 的值。

res.redirect

res.redirect() @ Express API

// 回到上一層路徑
// 例如,http://example.com/admin/post/new,則會回到 http://example.com/admin/post
res.redirect('..');

// 回到 referer 的網址,若沒有提供,則會回到 '/'
res.redirect('back');

常用工具

express-handlebars

const exphbs = require('express-handlebars');

app.engine('hbs', exphbs({ defaultLayout: 'main', extname: '.hbs' }));
app.set('view engine', 'hbs');

解析 body-parser, urlencoded, json

var express = require('express');

var app = express();

app.use(express.json()); // for parsing application/json
app.use(express.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded

app.post('/profile', function (req, res, next) {
console.log(req.body);
res.json(req.body);
});

使用 session:express-session

const session = require('express-session');
app.use(
session({
secret: 'secret',
resave: false,
saveUninitialized: false,
}),
);

使用 flash 提示訊息:connect-flash

// app.js
const flash = require('connect-flash');
const app = express();

app.use(express.session({ cookie: { maxAge: 60000 } }));
app.use(flash());

// STEP 1:把 flash 的值存到 locals
app.use((req, res, next) => {
res.locals.success_messages = req.flash('success_messages');
res.locals.error_messages = req.flash('error_messages');
next();
});
// controller
// STEP 2:在 controllers 中有需要時帶入 flash 訊息
app.get((res, res, next) => {
req.flash('success_message', 'some success messages');
});
<!-- 在 view 中使用 flash 訊息 -->
{{{success_message}}}

使用 GET 和 PUT 以外的 HTTP 方法:method-override

Controller

// app.js
const methodOverride = require('method-override');
app.use(methodOverride('_method'));

Routes

app.put('/restaurants/:restaurantId', (req, res) => {
/* ... */
});
app.delete('/restaurants/:restaurantId', (req, res) => {
/* ... */
});
<!-- form.html -->
<form action="/restaurants/{{restaurant.id}}?_method=PUT" method="POST">
<!-- ... -->
</form>

<form
action="/restaurants/{{this.id}}?_method=DELETE"
method="POST"
style="display: inline;"
>
<!-- ... -->
</form>

上傳圖片:multer

未來考慮使用 formidable @ npmjs

View

加上 enctype="multipart/form-data"

<form
action="/admin/restaurants/{{restaurant.id}}?_method=PUT"
method="POST"
enctype="multipart/form-data"
>
<div class="form-group">
<label for="image">Image</label>
<input type="file" class="form-control-file" name="image" id="image" />
</div>
</form>

Routes

使用 upload.single('image') 表示上傳一張圖片:

// routes
const multer = require('multer');
const upload = multer({ dest: 'temp/ ' }); // 把上傳的暫存檔存放到 temp 資料夾

// multer 只要看到 request 內有圖片,就會自動複製到 temp 資料夾
app.post('/admin/restaurants/', upload.single('image'), (req, res) => {
/* ... */
});

Controller

// Controller
const putRestaurant = async (req, res) => {
const { restaurantId } = req.params;
const { file } = req;
const { path, originalname } = file;
try {
if (file) {
const data = await fs.promises.readFile(path);
await fs.promises.writeFile(`upload/${originalname}`, data);
}

const restaurant = await Restaurant.findByPk(restaurantId);
await restaurant.update({
image: file ? `/upload/${originalname}` : restaurant.image,
});

req.flash('success_messages', '成功上傳圖片');
return res.redirect('/admin/restaurants');
} catch (error) {
req.flash('error_messages', `上傳圖片失敗(${error}`);
return res.redirect('/admin/restaurants/edit');
}
};

File 物件

// req.file
{
fieldname: 'image',
originalname: '1.jpeg',
encoding: '7bit',
mimetype: 'image/jpeg',
destination: 'temp/ ',
filename: '07b52fd0891d5a870bc885ed51ea060e',
path: 'temp/ /07b52fd0891d5a870bc885ed51ea060e',
size: 11245
}