1. HTML form의 기본 동작
- HTML form을 전송하면, 입력된 정보가 기본적으로
percent encoding
되어 요청된다.- GET method
GET /search?query=%EA%B0%9C&sort=latest HTTP/1.1 ..
- POST method
POST /form HTTP/1.1 Content-Type: application/x-www-form-urlencoded .. home=Cosby&favorite+flavor=flies
2. multipart/form-data
- 기본 설정(percent encoding)으로는 폼으로
파일을 업로드하는 것은 불가능
- (클라이언트 측) form 태그에
enctype="multipart/form-data"
속성을 적용하면 파일 업로드 가능 - (서버 측) body-parser 미들웨어는 multipart/form-data 형태의 요청을 지원하지 않음 (multer 필요)
======= HTML Form 예제 # =======
- 순수 HTML에서는 get과 post 만을 지원한다. 그래서 등록,수정,삭제 시 post를 사용한 것이다.
- Form validation : form을 통해서 사용자가 입력한 데이터를 원하는 데이터인지 검사하는 과정이 필요하다.
form validation을 구현하는 전형적인 방법
- 사용자가 폼을 작성합니다.
- 사용자가 폼을 서버에 전송합니다.
- 서버는 기대한대로 데이터가 들어왔는지 검사합니다.
- 서버는 데이터가 기대한 대로 잘 들어왔으면 다음 단계를 진행하고, 데이터에 문제가 있다면 어떤 문제가 있는지를 사용자에게 알려줍니다. (이 프로젝트에서는 데이터에 문제가 있으면 단순하게 400 Bad Request 응답을 하고 있지만 사용자 경험을 위해서는 이렇게 하면 안되겠죠?)
- 클라이언트 측 validation :
- javascript로 일일히 하나 다 짜는방법, submit 이벤트에 데이터 검사 방법
- HTML5 form validation : 내장되어 있어서 간편하고 모바일 측에서 좋지만, 복잡한 것에는 지원하지 않는다!!
- required
<input required type="text" name="title">
- 서버 측 validation : 클라이언트 측에서 했지만 꼭 서버 측에서도 해주어야 한다!!
-
redirect('/')
: 브라우저의 새로고침은 이전에 보냈던 요청을 다시 요청하는 것이다. 이렇기 때문에 redirect를 안해주면 같은 요청이 계속 가기 때문에 원하던 결과가 안 나올 수도 있다. 대신 ajax로 보낼 시에는 redirect가 아니어도 상관이 없지만, 순수 html형식으로 보낼 시에는 redirect를 써주는 것이 좋다.- 301 redirect: 웹브라우저에 정보를 기억 해놨다가 똑같은 요청이 오면 웹브라우저에 기억된 것을 실행
- 302 redirect: 똑같은 요청을 보내더라도 서버에 계속 정보를 요청할 때 (form같은 부류의 요청을 사용할 때)
-
UUID (Univer)
: 어떤 자료의 식별자를 만들 때 사용한다.- slug : url로 이 아이디가 무엇을 의미하는지를 알게 하고 싶을 때도 사용된다.
- UUID : 분산 데이터베이스를 사용 하면 어떤 것이 어떤 순서로 데이터가 들어온지 알 수가 없다. 이를 위해 데이터 하나하나에 고유한 식별자를 지정해준다. 이때 쓰는 것이 UUID이다. 이때 식별자들은 숫자이며 128 bit이다.
: 사용법은 uuid를 다운로드 한 후 다음과 같이 사용한다.
npm install uuid
const uuidv4 = require('uuid/v4')
const todos = [
{
id: uuidv4(),
title: 'sample todo'
}
]
======= HTML Form 예제 끝 =======
==== 실습 ====
<< 시나리오 >>
(관리자)
- 로그인
- 긴 URL을 폼에 입력하고 전송
- 서버에서 URL 변환
- 경과확인
짧은 URL 이용하기
(방문자 or 관리자)
- 짧은 URL 접속
- 301 응답
- 긴 URL로 리다이렉트 됨
URL 목록 열람
(관리자)
- 로그인
- 루트경로(/)에서 열람
<< 데이터 설계 >>
- 배열에 긴 URL을 longUrl, 짧은 URL을 id에 객체형태로 저장한다.
구현
<< 프로젝트 세팅 >>
- npm init -y
작업할 디렉터리를 생성한 후, .git을 생성해 준다.
$ git init -y
- .gitignore 추가
vscode 확장자에서 gitignore를 설치해준다.
add gitignore -> node를 선택하여 node_modules의 변경사항을 무시하는 gitignore를 생성할 수 있다.
node_modules는 깃 저장소에 넣지 않는 것이 원칙이다.
- node_modules를 깃에 올리지 않는 이유?
- git 저장소는 내 프로젝트의 코드를 관리하기 위한 곳이지 외부 패키지를 관리하기 위한 것이 아니다.
- git 저장소의 용량이 커지고 git이 추적해야 할 파일이 많아지기 때문에 느려질 수 있다.
<< Express 앱 세팅 >>
- install
$ npm install --save express
const express = require('express')
const app = express()
- 템플릿 엔진 설정
$ npm install --save ejs
app.set('view engine', 'ejs')
- static 라우트 설정
app.use('/static', express.static('public'))
<< 로깅과 인증 >>
- morgan 설정 : morgan - 서버에 요청이 들어올 때 어떤게 들어오는지 보여준다.
$ npm install --save morgan
const morgan = require('morgan')
app.use(morgan('tiny'))
- express basic auth 설정 install :
$ npm install --save express-basic--auth
const basicAuth = require('express-basic-auth')
app.use(basicAuth({
users: { 'admin': 'admin' },
challenge: true,
realm: 'Imb4T3st4pp'
}))
<< 초기 데이터 작업 >>
const data = [
{longUrl: 'http://google.com', id: '59DX23'}
]
// 짧은 url은 : http://localhost:3000/59DX23 접속하면
// 302 응답이 온다.
// 굳이 다 저장할 필요 없이 뒤에 것만 저장하자! /59DX23
<< 표로 보여주기 >>
그리고 확인 해보기 위해 server.js 와 index.ejs를 다음과 같이 코딩해준다.
// javascript
app.get('/', (req, res) => {
res.render('index.ejs', {data})
})
<!-- index.ejs -->
<table>
<thead>
<tr>
<td>Long URL</td>
<td>Short URL</td>
</tr>
</thead>
<tbody>
<% data.forEach(item => { %>
<tr>
<td><%= item.longUrl %></td>
<td><%= item.id %></td>
</tr>
<% }) %>
</tbody>
</table>
로딩해보면 다음과 같다.
<< randomstring >>
insall:
$ npm install --save randomstring
const randomstring = require('randomstring')
// data의 id를 랜덤 스트링으로 해준다.
const data = [
{longUrl: 'http://google.com', id: randomstring.generate(6)}
]
<< 짧은 URL의 리디렉션 >>
app.get('/:id', (req, res) => {
const id = req.params.id
const matched = data.find(item => item.id === id)
if(matched) {
res.redirect(301, matched.longUrl)
} else {
res.status(404)
res.send('404 Not Found')
}
브라우저가 저장하고 요청시 저장한 내용을 실행 하도록 301 요청을 하였다.
<< 폼 >>
- body-parser install:
$ npm install --save body-parser
const bodyParser = require('body-parser')
app.use(bodyParser.urlencoded({ extended: false }))
한 후, index.ejs 에 form을 만든다.
<form action="/" method="post">
<input type="url" name="longUrl" placeholder="url">
<input type="submit" value="전송">
</form>
// post, form으로 index.ejs에서 정보들을 가져온다.
app.post('/', (req, res) => {
const longUrl = req.body.longUrl
// id가 우연히 같은 것이 생성될 수도 있으니 let으로 선언해준다.
let id
while(true) {
const candidate = randomstring.generate(6)
const matched = data.find(item => item.id === candidate)
if(!matched) {
id = candidate
break
}
}
data.push({longUrl, id})
res.redirect('/') // 302 응답코드
})
그리고 text에 http://naver.com 을 입력한 후 전송을 누르면
<< now.sh를 통한 배포 >>
$ npm install -g now
$ now
e-mail입력하고, 메일로 가서 confirm 받은 후, 다시 한번 돌아와서 now를 실행하면 배포할 것인지 물어본다! 그때 y를 눌러서 배포된 url을 받는다!!
내가 받은 URL = https://urlshortner-flboillbut.now.sh