사용자의 정보를 입력받아 저장할 때는 Form
을 이용할 수 있다.
express
에서는 req.body
로 해당 데이터에 접근할 수 있는데,
아무런 설정을 하지 않는다면 해당 데이터는 undefined
로 저장이 된다.
app.use(express.urlencoded({ extended:true }));
우선, Form
은 클라이언트 측에서 정보를 받아 서버 측으로 전달할 때 사용하는 방법이다.
보통 action
과 method
속성을 주로 선언하는 것을 볼 수 있는데,
action
은 데이터를 수신하는 대상, 즉 "데이터가 어디로 전송되는 가?"이다.
아무런 설정을 하지 않으면 Form
이 위치한 URL로 데이터가 전송된다.
method
는 GET
방식과 POST
방식 2가지가 있다.
GET
방식
- action 값의 URL 뒤에
?key=value
의 형태로 데이터를 전송- 사용자가 URL에서 전송된 데이터를 볼 수 있음
- URL을 통해서 데이터를 전송하므로 정보량의 제한이 있음
request body
는null
값을 가짐
POST
방식
request body
로 데이터 값을 전달- 사용자는 해당 데이터 값을 직접적으로 볼 수 없음
(보안상 중요한 정보는 주로POST
방식을 이용)- 데이터의 용량의 제한이 없음
request header
를 통해 원하는 데이터 형식을 설정 할 수 있음
<form method="GET/POST", action="http://www.foo.com">
<input name="say" id="say" value="Hi">
<input name="to" id="to" value="Mom">
</form>
GET
의 경우
/// GET
GET / ?say=Hi&to=Mom HTTP/2.0
HOST : foo.com
request body
는 empty
인 상태
POST
의 경우
/// POST
POST / HTTP/2.0
HOST : foo.com
content-type : application/x-www-form-urlencoded
say=Hi&to=Mom
전달된 데이터는 request body
에 저장
header
에는 body
및 request / response
에 대한 정보가 포함됨
content-type
: 서버에 보낼 데이터의 타입
application/x-www-form-urlencoded
: URL 매개변수
로 인코딩 된 데이터 (Form
의 default
로 설정된 값)
urlencoding이란
url에 문자를 표기하기 위한 encoding 방식으로,
인터넷에서 URL은 ASCII 문자열을 이용해서만 전송될 수 있다.
따라서 ASCII 문자열에 포함되지 않는 문자 (ex, 특수문자)를 encoding해서
브라우저 차이에 의한 의도치 않은 변형을 방지한다.
위에서 살펴본 내용을 종합해보면, Form
에서 submit
된 데이터는 HTTP POST request
를 통해
request body
에 해당 데이터가 저장된 상태로 서버 측에 전달된다.
이때 express
에서 req.body
로 해당 데이터에 요청할 경우 undefined
값을 얻게 된다. 왜냐하면 req.body
의 default
값이 undefined
이기 때문이다.
따라서 req.body
를 통해 해당 데이터를 사용하고 싶다면 body-parser
를 통해 데이터를 가공해야 한다. body-parsing
이란 body
를 통해 전송된 데이터를 원하는 형태의 데이터로 가공하는 과정을 뜻한다.
다행히도 express
에서는 express.urlencoded
라는 middleware
를 지원하고 있다. 해당 middleware
는 request body
로 전송된 데이터를 parsing
하고, 해당 값을 req.body
에 저장하는 작업을 수행한다.
app.use(express.urlencoded({ extended : true }));
options
부분에 아무 값도 넣지 않으면 body-parser deprecated undefined extended: provide extended option
이라는 에러를 보게되는데, extended
옵션을 넣어주면 된다. true
로 설정할 경우 qs
모듈을 따로 설치해 주어야 하는데, 마침 express dependencies
에 해당 모듈이 포함되어 자동 설치돼 있다. This option allows to choose between parsing the URL-encoded data with the querystring library (when false) or the qs library (when true). The “extended” syntax allows for rich objects and arrays to be encoded into the URL-encoded format, allowing for a JSON-like experience with URL-encoded.
이제 어느 정도 form
을 통해서 데이터가 서버 측으로 전달되는 방식이 이해되는 것 같은데
특이한 녀석을 하나 발견했다.
바로 type="file"
의 데이터 전송이다.
HTTP protocol
의 경우 text protocol
이다. 쉽게 말하면 text
형태의 데이터를 전송하는 프로토콜이라는 의미다. 그런데 이미지 파일이나 비디오, 음성 파일을 form
을 통해 전송하려고 한다면...? 파일은 주로 binary protocol
을 이용하기 때문!
따라서 추가적인 설정이 필요한데,
method="POST"
방식을 이용할 것!input type="file"
로 설정할 것!form
속성에 enctype="multipart/form-data"
를 추가할 것!enctype
: header
에서 데이터 타입을 의미하는 content-type
을 선언할 수 있는 속성. default
값은 application/x-www-form-urlencoded
로 설정돼 있다.multipart/form-data
: 데이터가 전송될 때 각 파일과 body
로 데이터가 분할된다는 의미이렇게만 한다면 파일을 받아서 사용할 수 있겠지???
크나큰 오산이었다....
File
이 submit
되면 기본적으로 request body
안에 따로 전달되지 않기 때문에, body-parsing
처럼 추가적인 과정이 필요하다.
이때 도움을 주는 것이 NodeJS
의 미들웨어인 multer
이다.
multer
는form
을 통해 제출된 한 개 혹은 여러개의file
을 특정 경로에 저장하고, 관련 정보를req.file
에 저장해주는 역할을 수행한다. 또body-parser
처럼body
객체를request
객체 안으로 넣어주는 역할을 한다.
import multer from 'multer'
// middleware setting
const uploadFile = multer({ dest : "/uploads"});
app.post("/file", uploadFile.single("file"), controllers);
// "/file" 경로로 post 되는 from 데이터에 multer를 적용
// name="file" 값으로 제출되는 1개의 파일을 "/uploads" 경로에 저장
// file 관련 정보를 req.file에 저장
multer
는 post
되는 router
에서 미들웨어로 사용하면 된다.
uploadFile
에서 {}
에서 options
객체를 설정할 수 있다
req.file
에 저장되는 파일의 정보는 다음과 같다. multer
이후 실행된 controller
에서 해당 값을 사용할 수 있다.
DataBase
에는 관련 모든 정보가 아니라 path
정보만 입력하는 것을 기억하자!
fieldname
: form
에 정의된 field
명 (input name
에 설정된 값)originalname
: 사용자가 업로드한 파일 명encoding
: 파일의 엔코딩 타입mimetype
: 파일의 Mime 타입 (파일의 확장자)size
: 파일의 바이트(byte) 사이즈 destination
: 파일이 저장된 폴더path
: 업로드된 파일의 전체 경로 dest
or storage
: 파일이 저장될 위치limit
: 업로드 된 데이터의 한도 option
중 storage
를 사용하면, 저장 될 파일의 이름(기본 값은 랜덤한 이름)도 추가적으로 설정할 수 있다. req
와 file
에 접근할 수 있어서 해당 값을 사용해 설정할 수 있다.
const storage = multer.diskStorage({
destination : (req, file, cb) => {
cb(null, "/uploads")
// file이 저장될 경로
},
filename : (req, file, cb) => {
cb(null, file.originalname)
// 저장될 file의 이름
// file에 접근해서 originalname 값을 사용할 수 있다.
}
})
const uploadFile = multer({ storage : storage })
multer
까지 사용했으니 이제 file
업로드 할 수 있겠지...?
그런데 file
을 업로드해보니 왜 안되지...?
파일의 src
경로가 http://localhost:4000/uploads/file 여서 해당 경로로 접근을 하면 아무 일도 일어나지 않는다. 왜냐면 해당 경로로 접근했을 때 어떻게 처리할지 아무런 설정을 하지 않았기 때문이다.
그래서 해당 경로로 접근하면 특정 폴더의 파일을 넘겨줄 필요가 있다. 이때 사용하는 것이 express.static()이라는 미들웨어다.
express.static(root, [options])
express
에 내장된 미들웨어로, 이미지, css, js 파일과 같은 정적 파일의 접근을 허용할 수 있다. 즉, 서버 안의 특정 폴더를 열람할 수 있는 기능을 제공
app.use('/uploads', express.static('uploads'))
// "/uploads" 경로로 접근 시, uploads 폴더 안의 파일에 접근할 수 있다.
// 접근 경로와 폴더의 경로를 정확하게 입력해야 한다.
이것만 하면 진짜 끝...!
참고 자료
Sending form data MDN
Form MDN
Express_express.urlencoded()
Express_req.body
Multer