Menu

Express req.params, req.query, req.body 차이 정리

req.params는 경로의 이름 붙은 부분(/users/:id), req.query는 쿼리 문자열(?sort=new), req.body는 파싱된 요청 본문을 담습니다. req.body는 express.json() 같은 본문 파서를 추가하기 전까지 undefined입니다.

이 페이지에는 실행 가능한 에디터가 있습니다. 편집하고 실행하면 결과를 바로 볼 수 있습니다.

Express에서 req.params는 라우트 경로의 이름 붙은 세그먼트 값을(/users/:id라면 req.params.id), req.query는 ? 뒤의 쿼리 문자열을(/search?q=node라면 req.query.q), req.body는 요청 본문으로 보낸 데이터를 담습니다. req.params와 req.query는 모든 요청에서 채워지지만, req.body는 app.use(express.json()) 같은 본문 파서가 읽기 전까지 undefined입니다. params와 query의 값은 항상 문자열입니다.

첫 요청은 {"params":{"userId":"7"},"query":{"sort":"new","limit":"2"}}로 응답합니다. 따옴표를 보세요. 7과 2는 문자열이므로, 계산하거나 숫자와 비교하기 전에 Number()로 바꾸세요. 이제 메서드를 POST로 바꾸고, 경로는 /users/7/posts 그대로 두고, 본문 {"title": "Hello", "draft": true}를 보내세요. 201과 "body":{"title":"Hello","draft":true}가 돌아오는데, 여기서 true는 JSON에서 왔기 때문에 진짜 불리언입니다.

req.params vs req.query vs req.body

req.paramsreq.queryreq.body
출처경로, /users/:id쿼리 문자열, ?sort=new요청 본문
URL이나 본문 예/users/7/users?sort=new{"name": "Ada"}
값{ id: '7' }{ sort: 'new' }{ name: 'Ada' }
타입문자열문자열과 문자열 배열JSON에 담긴 그대로
필요한 설정라우트에 :name없음app.use(express.json())
주 용도어떤 리소스인지필터, 정렬, 페이지만들거나 수정할 데이터

라우트에는 매개변수가 여러 개 있을 수 있고, 각 이름이 req.params의 키가 됩니다. /teams/:teamId/members/:memberId라면 두 id를 모두 얻습니다. 하이픈이나 점으로도 나눌 수 있어서, /flights/:from-:to는 /flights/LAX-SFO를 { from: 'LAX', to: 'SFO' }로 바꿉니다.

키가 반복되거나 없을 때의 req.query

두 번 나오는 키는 배열이 되고 없는 키는 undefined이므로, 옵션에는 기본값을 주세요.

응답은 {"page":1,"tags":["red","sale"],"raw":{"tag":["red","sale"]}}입니다. GET /products?tag=red&page=3을 보내도 tags는 여전히 배열 ["red"]입니다. [].concat()이 문자열 하나든 배열이든 배열로 바꿔 주기 때문입니다. Express 5는 Node.js의 단순한 파서로 쿼리 문자열을 파싱하므로, ?filter[size]=m은 중첩 객체가 아니라 "filter[size]"라는 키가 됩니다. Express 4는 중첩시켰습니다.

req.body에는 express.json()이 필요합니다

Node.js는 본문을 바이트 스트림으로 넘깁니다. express.json()은 그것을 읽고 파싱해 req.body를 설정하지만, 요청에 Content-Type: application/json이 있을 때만 그렇게 합니다. HTML 폼은 application/x-www-form-urlencoded로 보내므로 대신 express.urlencoded()가 필요합니다.

본문 {"email": "ada@example.com"}로 POST /signup을 보내면 201과 {"email":"ada@example.com","name":"anonymous"}를 받습니다. 빈 본문을 보내면 400을 받습니다. ?? {}가 중요합니다. 이것이 없으면 JSON 본문이 없는 요청에서 undefined를 구조 분해하다가 TypeError가 발생합니다. 모양과 타입을 제대로 검증하려면 zod 같은 스키마 라이브러리를 쓰세요.

req.headers와 req.get()

req.headers는 모든 요청 헤더를 소문자 이름으로 담은 객체입니다. req.get(name)은 헤더 하나를 읽고 대소문자를 무시하므로, req.get('Content-Type')과 req.get('content-type')은 같은 값을 반환합니다. 자주 쓰는 다른 속성도 몇 가지 있습니다.

path는 /whoami, originalUrl은 /whoami?debug=1입니다. 요청 바에서 Authorization: Bearer abc 헤더를 추가하고 다시 보내면 token이 "Bearer abc"가 됩니다. app.use('/api', router)로 마운트한 라우터 안에서는 req.path에서 /api 접두사가 빠지지만 req.originalUrl에는 남아 있습니다(마운트는 Express 라우팅에서 설명합니다).

흔한 실수

GET 요청에서 req.body를 읽는 것. 브라우저와 대부분의 클라이언트는 GET에 본문을 보내지 않습니다. GET 옵션은 쿼리 문자열에 넣으세요.

쿼리 플래그를 truthy로 검사하는 것. ?admin=false는 문자열 'false'가 되고 이것은 truthy라서 if (req.query.admin)을 통과합니다. 문자열로 비교하세요. req.query.admin === 'true'입니다.

헤더 없이 JSON을 보내는 것. JSON을 text/plain으로 보내는 클라이언트는 req.body === undefined를 받습니다. 클라이언트에서 Content-Type: application/json을 설정하세요.

자주 묻는 질문

Express에서 클라이언트 IP 주소는 어떻게 얻나요?

req.ip를 읽으세요. 프록시나 로드 밸런서 뒤에서는 app.set('trust proxy', 1)을 설정하기 전까지 프록시의 주소가 나옵니다. 설정하면 Express가 대신 X-Forwarded-For 헤더를 읽습니다.

Express에서 요청의 전체 URL은 어떻게 얻나요?

req.originalUrl은 클라이언트가 보낸 그대로의 경로와 쿼리 문자열입니다. 절대 URL은 `${req.protocol}://${req.get('host')}${req.originalUrl}`로 만듭니다.

Express에서 파일 업로드는 어떻게 처리하나요?

파일 업로드는 multipart/form-data로 도착하는데, express.json()과 express.urlencoded()는 이것을 파싱하지 않습니다. multer 같은 패키지를 쓰면 파일은 req.file이나 req.files에, 나머지 필드는 req.body에 들어갑니다.

요청에서 쿠키는 어떻게 읽나요?

원본 헤더는 req.get('cookie')에 있습니다. req.cookies로 객체를 받으려면 cookie-parser 패키지를 설치하고 app.use(cookieParser())를 추가하세요.

Coddy 프로그래밍 언어 일러스트

Coddy로 코딩 배우기

시작하기