Form에서의 데이터 전송

NAMYUSEONG·2021년 12월 10일
0

사용자의 정보를 입력받아 저장할 때는 Form을 이용할 수 있다.
express에서는 req.body로 해당 데이터에 접근할 수 있는데,
아무런 설정을 하지 않는다면 해당 데이터는 undefined로 저장이 된다.

app.use(express.urlencoded({ extended:true }));

데이터 값을 받으려면 아래 값을 파일에 포함시키라고는 하는데, 이해가 잘 되지 않아 form에서 데이터를 전송하는 방식에 대해 찾아 봤다.

Form

우선, Form은 클라이언트 측에서 정보를 받아 서버 측으로 전달할 때 사용하는 방법이다.
보통 actionmethod 속성을 주로 선언하는 것을 볼 수 있는데,

action은 데이터를 수신하는 대상, 즉 "데이터가 어디로 전송되는 가?"이다.
아무런 설정을 하지 않으면 Form이 위치한 URL로 데이터가 전송된다.

methodGET 방식과 POST 방식 2가지가 있다.

GET 방식

  • action 값의 URL 뒤에 ?key=value의 형태로 데이터를 전송
  • 사용자가 URL에서 전송된 데이터를 볼 수 있음
  • URL을 통해서 데이터를 전송하므로 정보량의 제한이 있음
  • request bodynull 값을 가짐

POST 방식

  • request body 로 데이터 값을 전달
  • 사용자는 해당 데이터 값을 직접적으로 볼 수 없음
    (보안상 중요한 정보는 주로 POST 방식을 이용)
  • 데이터의 용량의 제한이 없음
  • request header를 통해 원하는 데이터 형식을 설정 할 수 있음

Form HTTP request

<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 bodyempty인 상태


POST의 경우

/// POST
POST / HTTP/2.0
HOST : foo.com
content-type : application/x-www-form-urlencoded
say=Hi&to=Mom

전달된 데이터는 request body에 저장
header에는 bodyrequest / response에 대한 정보가 포함됨

content-type : 서버에 보낼 데이터의 타입

application/x-www-form-urlencoded : URL 매개변수로 인코딩 된 데이터 (Formdefault로 설정된 값)

urlencoding이란

url에 문자를 표기하기 위한 encoding 방식으로,
인터넷에서 URL은 ASCII 문자열을 이용해서만 전송될 수 있다.
따라서 ASCII 문자열에 포함되지 않는 문자 (ex, 특수문자)를 encoding해서
브라우저 차이에 의한 의도치 않은 변형을 방지한다.


Express and Body parser

위에서 살펴본 내용을 종합해보면, Form에서 submit 된 데이터는 HTTP POST request를 통해
request body에 해당 데이터가 저장된 상태로 서버 측에 전달된다.


이때 express에서 req.body로 해당 데이터에 요청할 경우 undefined 값을 얻게 된다. 왜냐하면 req.bodydefault 값이 undefined 이기 때문이다.

따라서 req.body를 통해 해당 데이터를 사용하고 싶다면 body-parser를 통해 데이터를 가공해야 한다. body-parsing 이란 body를 통해 전송된 데이터를 원하는 형태의 데이터로 가공하는 과정을 뜻한다.

다행히도 express에서는 express.urlencoded라는 middleware를 지원하고 있다. 해당 middlewarerequest 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.


File upload와 multer

이제 어느 정도 form을 통해서 데이터가 서버 측으로 전달되는 방식이 이해되는 것 같은데
특이한 녀석을 하나 발견했다.

바로 type="file"의 데이터 전송이다.

HTTP protocol의 경우 text protocol이다. 쉽게 말하면 text 형태의 데이터를 전송하는 프로토콜이라는 의미다. 그런데 이미지 파일이나 비디오, 음성 파일을 form을 통해 전송하려고 한다면...? 파일은 주로 binary protocol을 이용하기 때문!

따라서 추가적인 설정이 필요한데,

1. method="POST" 방식을 이용할 것!

2. input type="file"로 설정할 것!

3. form 속성에 enctype="multipart/form-data"를 추가할 것!

  • enctype : header에서 데이터 타입을 의미하는 content-type을 선언할 수 있는 속성. default 값은 application/x-www-form-urlencoded로 설정돼 있다.
  • multipart/form-data : 데이터가 전송될 때 각 파일과 body로 데이터가 분할된다는 의미

이렇게만 한다면 파일을 받아서 사용할 수 있겠지???
크나큰 오산이었다....

Filesubmit 되면 기본적으로 request body안에 따로 전달되지 않기 때문에, body-parsing처럼 추가적인 과정이 필요하다.
이때 도움을 주는 것이 NodeJS의 미들웨어인 multer이다.

multer

multerform을 통해 제출된 한 개 혹은 여러개의 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에 저장

multerpost되는 router에서 미들웨어로 사용하면 된다.
uploadFile에서 {}에서 options 객체를 설정할 수 있다

file data

req.file 에 저장되는 파일의 정보는 다음과 같다. multer 이후 실행된 controller에서 해당 값을 사용할 수 있다.
DataBase에는 관련 모든 정보가 아니라 path 정보만 입력하는 것을 기억하자!

  • fieldname : form에 정의된 field 명 (input name에 설정된 값)
  • originalname : 사용자가 업로드한 파일 명
  • encoding : 파일의 엔코딩 타입
  • mimetype : 파일의 Mime 타입 (파일의 확장자)
  • size : 파일의 바이트(byte) 사이즈
  • destination : 파일이 저장된 폴더
  • path : 업로드된 파일의 전체 경로

options

  • dest or storage : 파일이 저장될 위치
  • limit : 업로드 된 데이터의 한도
  • ...등등

optionstorage를 사용하면, 저장 될 파일의 이름(기본 값은 랜덤한 이름)도 추가적으로 설정할 수 있다. reqfile에 접근할 수 있어서 해당 값을 사용해 설정할 수 있다.

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을 업로드해보니 왜 안되지...?

express.static()

파일의 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

profile
Divide and Conquer

0개의 댓글