nodemon
: 디렉토리 파일 변경 시 nodejs 서버 자동 재시작 해주는 라이브러리jest
: 테스팅 라이브러리portfinder
: 포트 검색용 라이브러리puppeteer
헤드리스 크롬 제어를 위한 nodejs 라이브러리eslint
: 코드에서 패턴을 검사하고 잘못된 부분을 보고하는 라이브러리express-validator
: 유효성 검사기
- 호스팅 지속적 통합 서비스
- github에서 무료로 사용 가능
//.eslintrc.js
module.exports = {
env: {
browser: true,
commonjs: true,
es2021: true,
jest: true, // jest 사용 명시
node: true, // node 사용 명시
},
globals: {
__dirname: true, // nodejs의 전역 변수 사용
},
extends: "eslint:recommended",
parserOptions: {
ecmaVersion: "latest",
},
rules: {},
};
http://localhost:3000/about?id=1#title
- `http -> 전송 프로토콜(Protocol)을 나타내는 스키마(Scheme)
localhost
-> 호스트 IP 또는 인터넷 도메인(Host domain):3000
-> 포트(Port)/about
-> 자원 경로(Path to resource)?id=1
-> 쿼리 스트링(Query string)#title
-> 앵커(Anchor) 또는 해시(Hash): 서버로 전송X
- HTTP 헤더에서
Content-Type
을 사용하여 지정 - 타입 / 서브 타입 / 옵션을 가짐
media-type
charset
boundary
GET
요청에는 없지만 일반적으로POST
요청 시 사용
Content-Type
을 설정하지 않은 경우 폼 데이터 전송 시 기본 값- &으로 구분되는 키-값 튜플 쌍
- 영문자 또는 숫자가 아닌 값은 URL로 인코딩 된다.
- 폼 데이터(FormData)를 전송하는데 사용
- 단순 문자열
- json을 통한 통신. 일반적인 데이터 전송 시 body에 객체를 담아 전송
- 지정된 경로에 매핑된 매개변수의 값을 가진 객체
// get /about/4234
app.get("/about/:id", (req, res) => {
console.log(req.params);
});
{ id: '4234' }
// get /about?page=1
app.get("/about", (req, res) => {
console.log(req.query);
});
{ page : '1' }
- 요청에 대한 본문으로 POST 요청 시에 사용
app.use(express.json()); // parse json
app.use(express.urlencoded({ extended: false })); // parse application/x-www-form-urlencoded
- 현재 일치하는 라우트에 관한 정보
- 클라이언트에서 전송한 쿠키 값 저장한 객체
- 클라이언트에서 전송한 요청 헤더
- 클라이언트가 주어진 타입을 받아들이는지 확인하는 편의 메서드
- 클라이언트의 IP 주소
- 요청 url중 경로 (path) 값
- 클라이언트에서 전송한 호스트 이름을 반환하는 편의 메서드
- 위조 가능성이 있어 보안 목적 사용 X
- 요청이 ajax 요청인지 확인하고 boolean값을 반환하는 편의 프로퍼티
- 요청에 사용된 프로토콜
- http 요청은 http 또는 https
- 암호화된 연결이면 true를 반환하는 편의 프로퍼티 (req.protocol === 'https')
- 경로와 쿼리 스트링을 반환
nodejs http.ServerResponse
의 인스턴스
- http 상태 코드 설정. 기본 값은 200(정상 응답)
- 응답 헤더를 설정
- 클라이언트에 저장될 쿠키를 설정
- 미들 웨어 필요
- 클라이언트에 저장될 쿠키를 삭제
- 브라우저를 리디렉트. 기본값은 302(발견됨)
- 페이지가 영구이동 되었을 때는 301(영구 이동됨)을 사용
- 클라이언트에 응답을 전송. 기본 콘텐츠 타입은
text/html
- json을 보낼 때는 res.json을 사용하는 것을 권장
- 클라이언트에 JSON을 전송
- 클라이언트에 JSONP을 전송
- 응답을 끝내고 연결을 끊는다.
Content-Type
헤더를 설정하는 편의 메서드res.set('Content-Type', type)
과 동등/
없는 type에 대해 자동으로 미디어 타입을 설정- 잘 사용하지 않음
- Accept 요청 헤더에 따라 콘텐츠를 다르게 전송하는 콘텐츠 협상을 수행
Accept
헤더는 MIME 타입으로 표현되고, 클라이언트가 이해가능한(Acceptable) 콘텐츠 타입을 알려준다.Accept
헤더 필드가 없는 경우에는 클라이언트가 모든 미디어 타입을 수락한다고 가정한다.Accept
헤더 필드가 있지만 허용가능한 타입의 응답이 없는 경우406(Not Acceptable)
에러를 응답해야 한다;q=1.0
매개변수를 사용하여 타입의 상대적 품질 계수를 0 ~ 1 사이 값으로 지정할 수 있다.text/html
을 지원하면 전송- 그렇지 않으면
application/xml
을 지원하면 전송 - 그렇지 않으면
*/*
를 지원하면 전송
- 값은
q
값을 가지는 유형이 둘 이상일 경우 더 구체적인 타입을 선택한다.
Accept : text/html, application/xml;q=0.9, */*;q=0.8
- 사용 가능한 값
<MIME_type>/<MIME_subtype>
: 서브 타입이 명시된 단일 MIME 타입<MIME_type>/*
: 서브 타입을 갖지않고 모든 서브 타입과 일치가능한 MIME 타입*/*
: 모든 MIME 타입
res.format({
"text/plain": function () {
res.send("hey");
},
"text/html": function () {
res.send("<p>hey</p>");
},
"application/json": function () {
res.send({ message: "hey" });
},
default: function () {
// log the request and respond with 406
res.status(406).send("Not Acceptable");
},
});
Content-Disposition
HTTP 응답 헤더를attachment
로 설정file name
을 지정하면 파일 이름과 확장자를 통해Content-Disposition
과Content-Type
을 자동으로 지정- 이렇게 헤더를 지정하면 브라우저는 콘텐츠를 렌더링하지 않고 파일 형태로 내려받는다.
- 헤더만 설정하고 파일 데이터는 따로 전송해야 한다.
res.attachment();
// Content-Disposition: attachment
res.attachment("path/to/logo.png");
// Content-Disposition: attachment; filename="logo.png"
// Content-Type: image/png
path
로 지정한 파일을 읽고, 파일 이름과 확장자를 통해Content-Type
을 설정하고 콘텐츠를 클라이언트에 전송
app.get("/file/:name", function (req, res, next) {
var options = {
root: path.join(__dirname, "public"),
dotfiles: "deny",
headers: {
"x-timestamp": Date.now(),
"x-sent": true,
},
};
var fileName = req.params.name;
res.sendFile(fileName, options, function (err) {
if (err) {
next(err);
} else {
console.log("Sent:", fileName);
}
});
});
view
를 렌더링하고 렌더링된 HTML 문자열을 클라이언트에 전송- 기본 응답 코드는 200
locals
: view에 대한 지역 변수를 정의하여 넘긴다callback
: 오류(err)와 렌더링된 문자열(html)을 반환하고 에러가 발생하면 호출된다.
// send the rendered view to the client
res.render("index");
// if a callback is specified, the rendered HTML string has to be sent explicitly
res.render("index", function (err, html) {
res.send(html);
});
// pass a local variable to the view
res.render("user", { name: "Tobi" }, function (err, html) {
// ...
});
const express = require("express");
const app = express();
const port = process.env.PORT || 3000;
app.get("/", (req, res) => {
res.send("Hello World!");
});
app.listen(port, () => {
console.log(`Example app listening on port ${port}`);
});
app.use((req, res) => {
res.type("text/plain");
res.status(404);
res.send("404 - Not Found");
});
지정된 경로로 지정된 메서드 요청이 들어오면 콜백 함수를 실행하고 res를 반환
app.METHOD(path, callback [, callback ...])
사용 가능한 메서드 목록
checkout
copy
delete
get
head
lock
merge
mkactivity
mkcol
move
m-search
notify
options
patch
post
purge
put
report
search
subscribe
trace
unlock
unsubscribe
app.get("/", (req, res) => {
res.send("Hello World!");
});
app.post("/", (req, res) => {
res.send("Got a POST request");
});
app.put("/user", (req, res) => {
res.send("Got a PUT request at /user");
});
app.delete("/user", (req, res) => {
res.send("Got a DELETE request at /user");
});
nodejs의 res.end()
http 응답을 보내기
Buffer
, String
, Object
, Boolean
, Array
헤더를 지정하지 않으면 매개변수 값에 따라 자동으로 지정
- 매개변수가
Buffer
일 때 ->application/octet-stream
- 매개변수가
String
일 때 ->text/html
- 매개변수가
Array
또는Object
일 때 -> JSON
nodejs의 res.writeHead
http 응답에 대한 헤더 설정, 여러 값을 지정해야 할 경우 객체 사용
res.set("Content-Type", "text/plain");
res.set({
"Content-Type": "text/plain",
"Content-Length": "123",
ETag: "12345",
});
nodejs의 response.statusCode
http 응답에 대한 상태 코드 설정
express에 내장된 미들웨어 기능으로 정적 파일을 제공
일반적으로 프로젝트 폴더 내의 public
폴더를 생성하여 사용
app.use(express.static("public"));
/public/img/logo.jpg
-> /img/logo.jpg
로 접근
- 오직 텍스트 데이터만 가진 form
const multer = require("multer");
const upload = multer();
app.post("/profile", upload.none(), function (req, res, next) {
// req.body contains the text fields
});
.
├── app.js
└── views
├── home.handlebars
└── layouts
└── main.handlebars
const engine = require("express-handlebars").engine;
app.engine("handlebars", engine());
// app.engine('handlebars', engine({ defaultLayout: 'main' }));와 동일한 기본값
app.set("view engine", "handlebars");
// pp.set('views', './views'); 기본값
app.get("/", (req, res) => res.render("home"));
app.get("/about", (req, res) => res.render("about", { name: "alyssa howell" }));
//레이아웃 없는 페이지 만들기 -> { layout: null }
exports.serverError = (err, req, res, next) =>
res.render("500", { layout: null });
- 현재 레이아웃은 body태그에 들어 있다
- 하지만 head 태그 안에 무언가를 넣거나 스크립트를 동작시켜야할 때도 있다.
app.engine(
"handlebars",
engine({
helpers: {
section: function (name, options) {
if (!this._sections) this._sections = {};
this._sections[name] = options.fn(this);
return null;
},
},
})
);
{{! 서버에서만 보이는 주석}}
<!-- 클라이언트에서도 보이는 주석 -->
- 반복문 안에서는 컨텍스트가 변경된다.
../
: 상위 컨텍스트로 변경
{
page: 1,
users: [
{name: 'foo', age: 20},
{name: 'bar', age: 32},
],
links: ['naver','daum','google']
}
- 문자열 배열에서 문자열 그대로 가져오기
- 기본 경로 :
/views/partials/file.handlebars
- 사용법