
인프런 - 모든 개발자를 위한 HTTP 웹 기본 지식
해당 포스팅은 위 강의를 수강하고 난 뒤 기존에 작성된 개인 프로젝트의 코드를 고치고 강의 내용을 적용해 보는 일련의 과정을 담고 있습니다.
코드의 부족한 점, http 관련 잘못된 내용들에 대해서는 댓글로 피드백 주시면 감사하겠습니다. 👨🏼🌾
웹 서비스를 이용하기 위해 회원가입을 하면 로그인, 프로필 업데이트, 로그아웃, 회원탈퇴 등 크게 4가지의 기능을 이용할 수 있습니다.
클라이언트에서 유저가 이 4가지 기능을 사용할 때 발생하는 서버와의 통신 과정을 어떻게 구성했는지 살펴보고 http 학습 내용을 바탕으로 해석해 보도록 하겠습니다.
export const loginAPI = (body: LoginAPIBody) =>
axios({
url: API_AUTH_LOG_IN,
method: "POST",
data: body,
headers: {
"carrot-status": "wilted",
},
});
if (req.method !== "POST") {
res.statusCode = 405;
return res.end();
}
POST가 아닌 경우 405 Method Not Allowed 상태코드로 응답합니다.const { email, password } = req.body;
if (!email || !password) {
res.statusCode = 400;
return res.send("필수 정보가 없습니다.");
}
400 Bad Request 상태코드로 응답합니다.const { User } = await connect();
const user: StoredUserType = await User.findOne({ email: email }).exec();
if (!user) {
res.statusCode = 404;
return res.send("해당 이메일에 해당하는 유저가 없습니다.");
}
404 Not Found 상태코드로 응답합니다.if (user && !comparePassword(password)) {
res.statusCode = 401;
return res.send("비밀번호가 일치하지 않습니다.");
}
401 Unauthorized 상태코드로 응답합니다.const { User } = await connect();
const user: StoredUserType = await User.findOne({ email }).catch(
(error: MongoError) => res.status(502).send(error.message)
)
502 Bad Gateway 상태코드로 응답합니다.500 Internal Server Error 상태코드로 응답합니다.res.setHeader(
"Set-Cookie",
`access_token=${token}; path=/; expires=${new Date(
Date.now() + 60 * 60 * 1000
).toUTCString()}; httponly`
);
return res.status(200).send(userdataWithoutPassword)

개발자도구 네트워크 탭에서 login api에 대한 header 명세를 보면 각각 요청과 응답에 설정한 헤더 값들이 잘 전송되고 있는 것을 확인할 수 있습니다.
requeset method, status code 등의 정보가 있습니다.ETag 헤더가 부여되었습니다. 이 외에 요청 헤더에 따른 콘텐츠 타입 정보와 응답 생성 날짜 정보가 추가되었습니다.Referer값을 통해 로그인 하기 전에 메인 페이지에 위치하고 있었음을 알 수 있습니다.User-Agent값을 통해 사용자 정보를 확인할 수 있으나 맹신할 수는 없는 정보입니다.로그아웃 요청 함수와 응답 함수의 코드를 살펴봅니다.
export const logoutAPI = (userId: string) =>
axios({
url: `${API_AUTH_LOG_OUT}/${userId}`,
method: "DELETE",
});
DELETE 메서드를 통해 로그아웃 요청을 보냅니다.export default async (req: NextApiRequest, res: NextApiResponse) => {
if (req.method === "DELETE") {
try {
const { User } = await connect();
await User.findByIdAndUpdate(req.query.id, { token: "" }).exec();
res.setHeader("Set-cookie", "access_token=; path=/; expires=; httponly");
return res.status(200).end();
} catch (error) {
res.statusCode = 500
return res.send(error)
}
}
return res.status(405).end();
};
502 Bad Gateway 상태코드로 응답합니다. 이 응답코드는 응답 서버가 다른 서버로부터 유효하지 않은 응답을 받았다는 것을 의미합니다.500 Internal Server Error 상태코드를 응답합니다.200 OK 상태코드와 Header에 포함된 쿠키 값, 만료 시간 등을 초기화한 뒤 응답합니다.
로그아웃이 정상적으로 처리되고 난 뒤 headers 정보 입니다.
DELETE method가 정상적으로 처리되었음을 General Headers에서 확인할 수 있습니다.Referer 헤더값으로 유저의 서비스 이용 패턴에 대한 정보를 얻을 수 있습니다.export const updateProfileImageAPI = ({ _id, profileImage }: UserProps) =>
axios.patch(API_SETTING_USER, { _id, profileImage });
export const updateUserNameAPI = ({ _id, name }: UserProps) =>
axios.patch(API_SETTING_USER, { _id, name });
PATCH 메서드를 사용하여 요청합니다.export default async (req: NextApiRequest, res: NextApiResponse) => {
if (req.method === "PATCH") {
User.findByIdAndUpdate(
{ _id: req.body._id },
{ [Object.keys(req.body)[1]]: Object.values(req.body)[1] },
{ new: true }
).catch(catcher);
res.statusCode = 201;
return res.end();
}
res.statusCode = 405;
return res.end();
};
201 Created 상태코드를 응답합니다.PATCH 이외의 메서드 접근은 405 Method Not Allowed 상태코드를 응답하고 연결을 종료합니다.201 Created 응답을 받았음을 알 수 있습니다./setting 경로에서 요청이 온 것을 확인할 수 있습니다.export const secessionAPI = (_id: string) =>
axios({
url: `${API_AUTH_USER}/${_id}`,
method: "DELETE",
})
DELETE 메서드를 통해 로그아웃 요청을 보냅니다.export default async (req: NextApiRequest, res: NextApiResponse) => {
const { User, Board, Comment, Replies } = await connect();
const { id } = req.query;
if (req.method === "DELETE") {
await User.deleteOne({ _id: id }).catch(catcher);
await Board.deleteMany({ author: id }).catch(catcher);
await Comment.deleteMany({ author: id }).catch(catcher);
await Replies.deleteMany({ author: id }).catch(catcher);
res.setHeader("Set-cookie", "access_token=; path=/; expires=; httponly");
return res.end();
}
return res.status(405).end();
};
DELETE 메서드 요청이 들어오면 쿼리 스트링으로 전달받은 유저 아이디로 DB에서 데이터를 식별하고 삭제 처리를 합니다.405 Method Not Allowed 상태코드를 응답합니다.
DELETE 메서드로 요청되었고 정상적으로 처리되었다는 200 OK 응답 코드를 받았습니다.200 OK를 응답받은 것으로 보아 default값인 것으로 추정됩니다.set-cookie 헤더에서 토큰값과 만료시간을 초기화 시켰고 잘 적용된 것을 확인할 수 있습니다.