인프런 - 모든 개발자를 위한 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
헤더에서 토큰값과 만료시간을 초기화 시켰고 잘 적용된 것을 확인할 수 있습니다.