(막간 보충 공부중)
어제 오늘은 이론을 배우고 정리하기보다 코드를 직접 써보는 일에 집중했다. 직전 프로젝트 때의 다른 팀들의 코드를 보면서 연구하고 우리 팀 프로젝트 코드에 적용해보았다.
사실은 집중이 잘 안 됐다. 이론상으로 작동되어야 하는 코드가 계속해서 턱턱 막히니 진도가 굼벵이보다도 느린 느낌이었고 이렇게 계속해도 되는가 의문이 들었다.
저녁에는 그래서 자바스크립트 문법을 공부하며 환기했다. 여태 코딩과 구글링을 하며 스치기라도 한 개념들이 한가득 쌓여있는 상태라 그런지, 아니면 죽치고 안 풀리는 문제가 아닌 다른 걸 보는 것만으로도 살 판이 난 건지, 꽤 심화 문법에 관한 책이었는데도 재밌게 읽었다.
언제나 같은 딜레마와 의문이긴 하지만… 지식을 읽고 배워서 어떻게 해야 코드를 한 줄이라도 써서 적용하고 내 걸로 만들어볼 수 있을까? 결국 맹렬한 속도로 까먹을 거라지만, 그래도 어떻게 해야 불씨라도 잘 보존시켜놓을 수 있을지. 이런 고민에 언제나 정답같이 들려오는 소리처럼, 고민할 시간에 무작정 한 줄이라도 써보는 게 맞는 걸까. 하지만 그 무작정 한 줄을 어떻게 쓰냐고. 뭔가 커다랗게 돌아가는 소프트웨어적인 맥락에서 어떻게 쓰이고 어떨 때를 위해 어떻게 만들어서 저장해놔야 하는지를 알고 싶다.
나는 예시를 알고 싶다. 진짜 이게 어디에 왜 쓰이는 것인지. 그래서 왜 필요한 건지를 알고 싶다... 너무 이상적이기만 한 생각인지도. 그래도 예시 코드에 중점을 두고 수집해 나가는 것도 나쁘지 않은 전략일 것 같다. 내 검색 능력이 떨어져서 그런지 몰라도, 생각보다 내가 궁금해하는 그 상황에 알맞은 예제 코드가 별로 없다. 검색하고, 나오는 코드마다 읽고 가치가 있는지 판단하고 취합하고 정리하고 하는 데 시간이 많이 걸릴 것이다. 시간이 좀 걸려도, 미래의 나를 위해 그런 예시들을 모으는 것이 더 나을까?
Express의 req.path와 req.route.path
http://localhost:3000/api/admin/user/:email 이라는 URI가 있을 때
// app.js
const router = require('./routes');
app.user('/api', router);
// routes/index.js
const router = express.Router();
const adminRouter = require('./amin.routes');
router.use('/admin', adminRouter);
module.exports = router;
// routes/admin.routes.js
const router = express.Router();
const adminController = new require('../controllers/admin.controller)();
router.get('/user/:email', adminController.searchUser);
module.exports = router;
- req.route.path === ‘/user/:email’ 이런 용례와
- req.path === ‘/api/admin/user’ 이런 용례로 사용할 수 있다.
1. 관리자가 아닐 시 페이지 렌더링 막기
1. 관리자가 아닐 시 페이지 렌더링 막기
페이지에 가서 로그인 상태인지, 관리자인지를 체크하지 말고, (그러기 전에 이미 서버에서 다 렌더링 해서 줘버린 상태일 것이므로 좋지 않다…) 아예 렌더링을 담당하는 서버 계층에서 html을 보내줄 것인지 말 것인지를 결정하도록 하자.
DON’T
이렇게 하지 말고 :
// views/admin_orders.ejs
<script>
// 페이지 진입 시
if(localStorage.getItem('is_admin')!=='1'){
alert('관리자 권한이 없습니다.')
location.href='/'
}
// 페이지 로딩 완료 시
$(document).ready(function () {
me()
showOrderTables();
});
</script>
⇒ 렌더링 완료된 페이지가 살짝 보이는 것을 막을 수 없음.
DO
이렇게 하자:
// pages.routes.js
router.get('/admin/orders', authMiddleware, (req, res, next) => {
try {
// 로그인을 하지 않은 경우
에러 던지기
// 로그인을 했지만 관리자가 아닌 경우
에러 던지기
// 관리자인 경우
res.render('admin_orders.ejs', { components: 'orderManagement' });
} catch (error) {
// 던져진 에러를 받아서 next로 넘김
next(error);
}
});
⇒ route 단계에서 try-catch 문으로 갈랐다.
2. 모든 request-response 사이클에서 던진 에러 받아 처리하기
2. 모든 request-response 사이클에서 던진 에러 받아 처리하기
위의 예시처럼
} catch (error) {
// 던져진 에러를 받아서 next로 넘김
next(error);
}
이렇게 next(error)로 넘긴 모든 에러에 대한 처리는, 도입된 미들웨어들이 ‘위에서부터 순차적으로 처리된다’는 Express의 원리를 이용해 에러 처리 미들웨어를 가장 밑에 붙여두면 된다.
- 에러 처리 미들웨어를 만들고:
// middleware/error-handler.js
module.exports = (err, req, res, next) => {
/* 페이지 렌더링 처리 */
if (err.message === '로그인이 필요합니다') {
return res.render('modal.ejs', { message: err.message, href: '/login'});
}
if (err.message === '관리자 권한이 필요합니다') {
return res.render('modal.ejs', { message: err.message, href: '/'});
}
// ...
}
- Express app이 거치는 가장 마지막 미들웨어가 되도록 위치시킨다:
// app.js
const pageRouter = require('./routes/pages.routes');
const errorHandler = require('./middleware/error-handler');
/* ... 각종 app.use()들 ... */
app.use(pageRouter); // --> 페이지를 렌더링하는 라우터
app.use(errorHandler); // --> 각종 에러가 이 끝 미들웨어 함수로 모이게 됨.
- 그런데 같은 이름의 에러가 여러 곳에서 발생한다고 할 때, errorhandle.js 상단에서 이미 res.render()로 모든 ‘로그인이 필요합니다’ 에러에 대한 응답을 반환해버리는데, 따로 어떻게 또 res.json() 등의 예외 처리 케이스까지 도달하게 하지..?
3. 문제 발견
3. 문제 발견
기존의 auth-middleware에서
module.exports = (req, res, next) => {
const { authorization } = req.headers;
const [authType, authToken] = (authorization || '').split(' ');
if (!authToken || authType !== 'Bearer') {
res.status(401).send({
errorMessage: '로그인이 필요한 기능입니다.',
});
return;
}
try {
const { user_id } = jwt.verify(...)
}...
이런 방식은 반드시 HTTP 요청이 발생했을 때만 사용자 인증이 가능하다는 문제를 발견했다. 프론트에서 Ajax 요청을 보내지 않는 단순한 페이지 이동일 시, res.locals.users에 유저 확인 정보를 담는 이 방식으로는 계속해서 ‘로그인이 필요한 기능입니다’라고만 페이지를 띄울 뿐이다. 프론트 쪽에서 페이지 로딩이 될 때마다 /users/me를 호출하게 만드는 방식으로 해결할 수 있지만, 이는 서버쪽에서의 해결이 아니다.
location.href = ‘/admin_index’를 활성화하는 시점에 /users/me를 호출하게 하거나 Authorization header를 넣어주거나 하는 방법은 없을까?
페이지가 로딩되는 시점에 일단 me()를 호출하고, 바로 이어서 페이지 자체를 렌더링해주는 api를 또 호출하게 하는 식은 안될까?
Uploaded by N2T