Section 27: An Introduction to Node.js - A Different JavaScript Environment
The goals
๐ช๐ปWhat Exactly Is Node.js
โ๐ปWriting Node.js Code
๐๐ปUsing Express.js
๐๐ปTalking to a Database
How to use File System
const fs = require('fs');
fs.readFile('user-data.txt', (err, data) => {
if (err) {
console.log(err);
return;
}
console.log(data.toString());
});
fs.writeFile('user-data.txt', 'username=Max', err => {
if (err) {
console.log(err);
} else {
console.log('Wrote to file!');
}
});
Pure-node.js
const http = require('http');
const server = http.createServer((request, response) => {
let body = [];
request.on('data', chunk => {
body.push(chunk);
});
request.on('end', () => {
body = Buffer.concat(body).toString();
let userName = 'Unknown User';
if (body) {
userName = body.split('=')[1];
}
response.setHeader('Content-Type', 'text/html');
response.write(
`<h1>Hi ${userName}</h1><form method="POST" action="/"><input name="username" type="text"><button type="submit">Send</button></form>`
);
response.end();
});
});
server.listen(3000);
response.setHeader
Express.js
body-parser
EJS
Cross-Origin Resource Sharing (CORS)
๋์ผํ ์ถ์ฒ๊ฐ ์๋ ๋ค๋ฅธ ์ถ์ฒ์์ ๋ฐ์ดํฐ๋ฅผ ์ฃผ๊ณ ๋ฐ๋ ๊ฒ์ ํ์ฉํ๋ ์ ์ฑ
Cross-Origin Resource Sharing (CORS) is an HTTP-header based mechanism that allows a server to indicate any origins (domain, scheme, or port) other than its own from which a browser should permit loading resources. CORS also relies on a mechanism by which browsers make a "preflight" request to the server hosting the cross-origin resource, in order to check that the server will permit the actual request. In that preflight, the browser sends headers that indicate the HTTP method and headers that will be used in the actual request.
An example of a cross-origin request: the front-end JavaScript code served from https://domain-a.com uses XMLHttpRequest to make a request for https://domain-b.com/data.json.
For security reasons, browsers restrict cross-origin HTTP requests initiated from scripts. For example, XMLHttpRequest and the Fetch API follow the same-origin policy. This means that a web application using those APIs can only request resources from the same origin the application was loaded from unless the response from other origins includes the right CORS headers.
The CORS mechanism supports secure cross-origin requests and data transfers between browsers and servers. Modern browsers use CORS in APIs such as XMLHttpRequest or Fetch to mitigate the risks of cross-origin HTTP requests.
Same Origin Policy(๋์ผ ์ถ์ฒ ์ ์ฑ )
๋์ผ ์ถ์ฒ ์ ์ฑ ์ ์น ๋ธ๋ผ์ฐ์ ์์ ๋ณด์์ ๊ฐํํ๊ธฐ ์ํ์ฌ ๋์ผํ ์ถ์ฒ์์๋ง ๋ฆฌ์์ค๋ฅผ ์ฃผ๊ณ ๋ฐ๋๋ก ํ๋ ์ ์ฑ ์ด๋ค.
๊ทธ๋ ๋ค๋ฉด "์ถ์ฒ"๋ ๋๋์ฒด ๋ฌด์์ผ๊น?
์ฝ๊ฒ ๋งํ๋ฉด URL ์ฃผ์์ด๋ค. (๋จผ์ URL์ ๊ตฌ์ฑ์์๋ฅผ ๋ชจ๋ฅด๋ ๋ถ๋ค์ ์ฌ๊ธฐ ์์ ๋จผ์ ์ฝ๊ณ ์ค๊ธธ ๋ฐ๋๋ค.)
ํ์ง๋ง "๋์ผํ ์ถ์ฒ"๋ ์ ํํ ๋๊ฐ์ URL์ ์๋ฏธํ๋ ๊ฒ์ ์๋๋ค.
๋์ผํ ์ถ์ฒ๋ URL ์ค์์๋ ํ๋กํ ์ฝ, ๋๋ฉ์ธ ์ฃผ์, ํฌํธ ๋ฒํธ๊ฐ ๊ฐ์ ๊ฒ์ ์๋ฏธํ๋ค.
์๋ฅผ ๋ค๋ฉด ์๋์ ๊ฐ๋ค.
CORS
๋ค์ CORS๋ก ๋์์์ ์ด๋ฌํ ๋์ผ ์ถ์ฒ ์ ์ฑ ์ด ์๊ธฐ ๋๋ฌธ์ ์๋๋ ๋ค๋ฅธ ์ถ์ฒ์์ ๋ฆฌ์์ค๋ฅผ ๋ฐ์์ค๋ ๊ฒ์ด ์ ํ๋๋ค.
ํ์ง๋ง ๋ค๋ฅธ ์ถ์ฒ๋ก๋ถํฐ ๋ฆฌ์์ค๋ฅผ ๋ฐ์์ค๋ ๊ฒ์ ํ์ ์์๊ฐ ๋์๊ณ , ์ด๋ฌํ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ๋์จ ์ ์ฑ ์ด ๋ฐ๋ก CORS(๊ต์ฐจ ์ถ์ฒ ์์ ๊ณต์ )์ด๋ค.
๊ทธ๋ ๋ค๋ฉด CORS๋ ์ด๋ป๊ฒ ์์ ํ๊ฒ ๋ค๋ฅธ ์ถ์ฒ์ ๋ฆฌ์์ค๋ฅผ ๊ณต์ ํ๋ ๊ฒ์ผ๊น?
๋ฐ๋ก ๋ ๊ฐ์ง ๋ฐฉ๋ฒ์ด ์๋๋ฐ, ๋จ์ ์์ฒญ ๋ฐฉ๋ฒ๊ณผ ์๋น ์์ฒญ ๋ฐฉ๋ฒ์ด ์๋ค.
Header
์์ฒญ ๋ฐฉ๋ฒ์ ์์ฒญํ๋ ํค๋์ ์๋ตํ๋ ํค๋๋ฅผ ํตํด์ ์ด๋ฃจ์ด ์ง๋ค.
์์ฒญ ํค๋
1. Access-Control-Request-Method
์์ฒญ์ ํ ๋ ์ด๋ค ๋ฉ์๋๋ฅผ ์ฌ์ฉํ ๊ฒ์ธ์ง๋ฅผ ์๋ ค์ฃผ๋ ๊ฒ์ด๋ค.
2. Access-Control-Request-Headers
์์ฒญ์ ํ ๋ ์ด๋ค ํค๋๋ฅผ ์ฌ์ฉํ ๊ฒ์ธ์ง ์๋ ค์ฃผ๋ ๊ฒ์ด๋ค.
์๋ต ํค๋
1. Access-Control-Allow-Origin
๋ฆฌ์์ค์ ์ ๊ทผํ ์ ์๋๋ก ํ์ฉํ๋์ง๋ฅผ ์๋ ค์ฃผ๋ ๊ฒ์ด๋ค.
2. Access-Control-Expose-Headers
๋ธ๋ผ์ฐ์ ์๊ฒ ์ ๊ทผํ ์ ์๋ ๋ฆฌ์คํธ๋ค์ ์๋ ค์ฃผ๋ ๊ฒ์ด๋ค.
3. Access-Control-Max-Age
์บ์ฑ๋๋ ์๊ฐ์ ์๋ ค์ฃผ๋ ๊ฒ์ด๋ค.
4. Access-Control-Allow-Credentials
ํฌ๋ ๋ด์ ์ด true์ผ ๋ ์์ฒญํ ์ง์ ๋ํ ๊ฒ์ ์๋ ค์ฃผ๋ ๊ฒ์ด๋ค.
5. Access-Control-Allow-Methods
ํ์ฉ๋๋ ๋ฉ์๋๋ฅผ ์๋ ค์ฃผ๋ ๊ฒ์ด๋ค.
6. Access-Control-Allow-Headers
์ฌ์ฉ ๊ฐ๋ฅํ HTTP ํค๋๋ฅผ ์๋ ค์ฃผ๋ ๊ฒ์ด๋ค.
์ด์ ํค๋์ ๋ํด ์์ ๋ณด์์ผ๋ ๋ณธ๊ฒฉ์ ์ผ๋ก ์์ฒญ์ ๋ํด ๋ค๋ค๋ณด๋๋ก ํ์.
Preflight Request (์๋น ์์ฒญ)
์๋น ์์ฒญ์ ๋ง ๊ทธ๋๋ก ๋ฏธ๋ฆฌ ์์ฒญ์ ๋ณด๋ด๋ณด๊ณ , ์์ ํ์ง๋ฅผ ํ๋จํ ๋ค์ ๋ณธ๊ฒฉ์ ์ผ๋ก ์์ฒญ์ ํ๋ ๋ฐฉ์์ด๋ค.
์๋์ ๊ฐ์ด ์๋น ์์ฒญ์ ๋ณด๋ด๊ณ ๊ทธ์ ๋ํ ์๋ต์ ๋ฐ์ ๋ค ์ค์ ์์ฒญ์ ๋ณด๋ด๊ณ ์๋ต๋ฐ๊ฒ ๋๋ค.
์กฐ๊ธ ๋ ๊ตฌ์ฒด์ ์ผ๋ก ๋งํ๋ฉด ํค๋์ Access-Control-Request-Method๋ฅผ ํตํด ์์ฒญํ๋ HTTP ๋ฉ์๋ GET,POST,PUT,DELETE ์ค ํ๋์ ๋ฉ์๋์ Access-Control-Request-Headers๋ฅผ ํตํด OPTIONS๋ผ๋ ํค๋๋ฅผ ๋ฃ๊ณ ์์ฒญ์ ๋ณด๋ธ๋ค.
์ด ๋ ์๋น๋ก ํ์ธํ๋ ๊ฒ ๋ฟ์ด๊ธฐ ๋๋ฌธ์ ๋ฐ๋์ ์๋ฌด๊ฒ๋ ์์ฑํ์ง ์๊ณ ํค๋๋ง ๋ณด๋ธ๋ค,
ํด๋น ๋ฉ์๋์ ํค๋๊ฐ ์ ํจํ๋ค๋ฉด ์๋ฒ๋ ์๋ต ํค๋๋ฅผ ํตํด ์ ๊ทผ ๊ฐ๋ฅํ์ง(Access-Control-Allow-Origin), ์ฌ์ฉํ ์ ์๋ ๋ฆฌ์์ค์ ๋ฆฌ์คํธ(Access-Control-Expose-Headers), ์บ์ฑ ๋๋ ์๊ฐ(Access-Control-Max-Age) ๋ฑ์ ์๋ ค์ฃผ๋ ๊ฒ์ด๋ค.
Simple Request (๋จ์ ์์ฒญ)
๋จ์ ์์ฒญ์ ์์ ์๋น ์์ฒญ๊ณผ๋ ๋ฌ๋ฆฌ ์๋ฒ์ ๋ฐ๋ก ๋ณธ๊ฒฉ์ ์ผ๋ก ์์ฒญ์ ์์ํ๋ค.
๊ทธ๋ ๋ค๋ฉด ๋ฏธ๋ฆฌ ํ์ธํ์ง๋ ์๊ณ ์ด๋ป๊ฒ ์์ ํ๊ฒ ๋ฆฌ์์ค๋ฅผ ์์ฒญํ๋ ๊ฒ์ผ๊น?
๊ทธ ๋ฐฉ๋ฒ์ ์กฐ๊ธ ๊น๋ค๋ก์ด ์กฐ๊ฑด๋ค์ ๊ฑฐ๋ ๊ฒ์ด๋ค.
1. Access-Control-Request-Method๋ฅผ ํตํด ์์ฒญํ ๋ ๋ฉ์๋๋ HTTP ๋ฉ์๋๊ฐ ์๋ GET,HEAD,POST ์ค ํ๋์ฌ์ผ ํ๋ค.
2. Access-Control-Request-Headers ํตํด ์์ฒญ์ ๋ณด๋ผ ๋ Accept Accept-Language,Content-Language, Content-TypeDPR, Downlink, Save-Data, Viewport-Width ์ค ํ๋์ฌ์ผ ํ๋ค.
3. Content-Type์ ์ฌ์ฉํ ๊ฒฝ์ฐ application/x-www-form-urlencoded, multipart/form-data, text/plain ์ค ํ๋์ฌ์ผ ํ๋ค.
์ด๋ ๊ฒ ๊น๋ค๋ก์ด ์กฐ๊ฑด์ ๊ฑธ๊ณ ํด๋น ์กฐ๊ฑด์ ๋ถํฉํ๋ค๋ฉด ์์ ํ ์์ฒญ์ด๋ผ ์ธ์ํ๊ณ ๋ฐ์ดํฐ๋ฅผ ์๋ตํ๋ ํ์์ด๋ค.
์ด ์น์ ์ ์์ฑ๋ ์ฝ๋๋ ์๋ชป๋ ID(ํน์ MongoDB ObjectId ์ ํ์ผ๋ก ๋ณํํ ์ ์์)๋ก /my-place/:id๋ฅผ ๋ฐฉ๋ฌธํ๋ ค๊ณ ํ๋ฉด ์ถฉ๋ํฉ๋๋ค.
๋ฌผ๋ก ์ด์ ๊ฐ์์์ ๋ฐฐ์ด ๊ฒ๊ณผ ์ ์ฌํ ๋ฐฉ์์ผ๋ก ์ค๋ฅ ์ฒ๋ฆฌ๋ฅผ ์ถ๊ฐํ ์ ์์ต๋๋ค.
- ๋๊ธฐ ์ฝ๋์ ๊ฒฝ์ฐ try-catch (๋๋ async/await)
- (async/ await์ ์ฌ์ฉํ์ง ์๋) ํ๋ก๋ฏธ์ค ๊ธฐ๋ฐ ์ฝ๋์์๋ then() / catch()
์์:
router.get('/location/:lid', (req, res, next) => {
const locationId = req.params.lid;
client.connect(function(err, client) {
const db = client.db('locations');
// Insert a single document
db.collection('user-locations').findOne(
{
_id: new mongodb.ObjectId(locationId)
},
function(err, doc) {
// if (err) {}
if (!doc) {
return res.status(404).json({ message: 'Not found!' });
}
res.json({ address: doc.address, coordinates: doc.coords });
}
);
});
});
์ ์์๋ ์๋์ ๊ฐ์ด ๊ฐ์ ๋ ์ ์์ต๋๋ค.
router.get('/location/:lid', (req, res, next) => {
const locationId = req.params.lid;
client.connect(function(err, client) {
const db = client.db('locations');
// ์ถ๊ฐ๋ ๋ถ๋ถ
let locationId;
try {
locationId = new mongodb.ObjectId(locationId);
} catch (error) {
// ๋ค๋ฅธ ์ฝ๋๊ฐ ์คํ๋์ง ์๋์ง ํ์ธํ๊ธฐ ์ํ return ๋ฌธ
return res.status(500).json({message: 'Invalid id!'});
}
// ์ถ๊ฐ๋ ์ฝ๋์ ๋ง์ง๋ง
// ๋จ์ผ ๋ฌธ์ ์ฝ์
db.collection('user-locations').findOne(
{
_id: locationId // ์๋ถ๋ถ์ ์ฝ๋์ ์ค๋ฅ๊ฐ ์๋ค๋ฉด ์ฌ๊ธฐ๊น์ง ๋๋ฌ
},
function(err, doc) {
// if (err) {}
if (!doc) {
return res.status(404).json({ message: 'Not found!' });
}
res.json({ address: doc.address, coordinates: doc.coords });
}
);
});
});
์ฌ๊ธฐ์ ์ค์ํ ์ ์ ๋ธ๋ผ์ฐ์ ์ธก JavaScript์ ๋์ผํ ์ค๋ฅ ์ฒ๋ฆฌ ๋๊ตฌ๊ฐ ์๋ค๋ ๊ฒ๋๋ค.
Sources
Express - Node.js web application framework
Fast, unopinionated, minimalist web framework for Node.js $ npm install express --save
expressjs.com
EJS -- Embedded JavaScript templates
Simple syntax JavaScript code in simple, straightforward scriptlet tags. Just write JavaScript that emits the HTML you want, and get the job done!
ejs.co
https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
Cross-Origin Resource Sharing (CORS) - HTTP | MDN
Cross-Origin Resource Sharing (CORS) is an HTTP-header based mechanism that allows a server to indicate any origins (domain, scheme, or port) other than its own from which a browser should permit loading resources. CORS also relies on a mechanism by which
developer.mozilla.org
https://fomaios.tistory.com/entry/Network-CORS%EB%9E%80-feat-%EB%B3%B4%EC%95%88HTTP
[Network] CORS๋? (feat. ๋ณด์,HTTP) (What is a CORS?)
CORS๋? CORS๋ Cross-Origin Resource Sharing์ ์ฝ์๋ก ์ง์ญํ๋ฉด "๊ต์ฐจ ์ถ์ฒ ๋ฆฌ์์ค ๊ณต์ " ์ด๋ค. ์ข ๋ ์ฝ๊ฒ ๋งํ๋ฉด ๋์ผํ ์ถ์ฒ๊ฐ ์๋ ๋ค๋ฅธ ์ถ์ฒ์์ ๋ฐ์ดํฐ๋ฅผ ์ฃผ๊ณ ๋ฐ๋ ๊ฒ์ ํ์ฉํ๋ ์ ์ฑ ์ด๋ค. ๊ทธ๋ ๋ค
fomaios.tistory.com