ChatterBox sprint 를 진행하면서. client와 server의 역할. 그리고 세부적인것들을 알아보았다.
서비스를 제공(serve)하는 컴퓨터로, 다수의 클라이언트 컴퓨터의 요청을 처리하기 위해 존재
Web Server, File Server 등
웹페이지 지원이나, 공유 데이터의 처리 및 저장 등의 비즈니스 로직을 주로 수행
터미널의 역할을 수행하는 컴퓨터
웹 브라우저는 대표적인 터미널
사용자 입력을 주로 수행
서버에 대한 응답을 화면에 표시
현대의 복잡한 시스템은 클라이언트이면서 서버의 역할을 동시에 수행하는 경우도 있음 (e.g. P2P)
클라이언트와 서버는 프로토콜(Protocol)이라고 불리는 정해진 규약에 따라 메시지를 교환
클라이언트는 서버가 어떤식으로 요청을 처리하는지에 대해선 구체적으로 알 필요없이, 추상화된 인터페이스(API; Application programing Interface)를 바탕으로 원격 서버에 요청(RPC; Remote Procedure Call)을 하고, 응답에 대해 적절한 형태로 화면에 표시
Background
const app = { server: 'http://localhost:3000/messages', init: () => { app.fetch() }, fetch: () => { //fetch API 를 통해 GET 요청을 제출. fetch(app.server) // 할당안해주면 GET 으로 감. .then((data) => data.json()) // GET 요청으로 받은 data 객체를 json() 해서 받음. .then((json) => { json.results.forEach((el) => app.renderMessage(el)); // json화 된 data를 렌더메소드의 매개변수로 받음. }) }, send: (message) => { // fetch API 를 통해 POST 요청 제출. fetch(app.server, { method: 'POST', body: JSON.stringify(message), // message 를 JSON.stringify 해서 서버에 요청. headers: { "Content-Type": "application/json", // hearder 설정 } }).then((data) => data.json()) // POST요청을 통해 서버에서 받은 data를 json() 해서 받음 .then((json) => { app.renderMessage(json); // json() 화 된 data를 렌더메소드의 매개변수로 받음. }) }, clearMessages: () => { //clearMessages 를 통해 출력된 메세지 목록을 지움. document.querySelector("#chats").textContent = ""; }, renderMessage: message => { // rendering let chats = document.querySelector("#chats") let main = document.createElement('div') main.className = 'chat' let user = document.createElement('div') user.className = 'username' user.textContent = message.username let msg = document.createElement('div') msg.className = 'message' msg.textContent = message.text let date = document.createElement('div') date.className = 'date' date.textContent = message.date let room = document.createElement('div') room.className = 'roomname' room.textContent = message.roomname; main.append(user, msg, date, room) chats.prepend(main) } }
DOM 조작은 따로 설명하지 않겠다.
클라이언트를 만듦으로써 CORS의 header와 body가 왜 중요한지.
그리고 JSON.stringify 와 JSON.parse 의 용도를 알게되었다.
const http = require("http"); const port = 3000; const ip = "127.0.0.1"; let message = { results: [] }; server.listen(port, ip); const server = http.createServer((request, response) => { if (request.method === "OPTIONS") { response.writeHead(200, defaultCorsHeaders); response.end(); } else if (request.method === "GET" && request.url === "/messages") { response.writeHead(200, defaultCorsHeaders); response.end(JSON.stringify(message)); } else if (request.method === "POST" && request.url === "/messages") { let body = []; request .on("data", (chunk) => { body.push(chunk); }) .on("end", () => { body = Buffer.concat(body).toString(); message.results.push(JSON.parse(body)); response.writeHead(201, defaultCorsHeaders); //201 Created 요청이 성공적이었으며 그 결과로 새로운 리소스가 생성, //이 응답은 일반적으로 POST 요청 또는 일부 PUT 요청 이후에 따라옵니다. response.end(JSON.stringify(message)); }) } else { // 매칭되는 주소가 없으면 response.statusCode = 404; // 404 상태 코드 response.end('주소가 없습니다'); } const headers = defaultCorsHeaders; headers["Content-Type"] = "application/json"; const defaultCorsHeaders = { "access-control-allow-origin": "*", "access-control-allow-methods": "GET, POST, PUT, DELETE, OPTIONS", "access-control-allow-headers": "content-type, accept", "access-control-max-age": 10 // Seconds. }
const express = require('express') const app = express() const cors = require('cors') // cors 미들웨어 const bodyParser = require('body-parser') // body-parser 미들웨어 const jsonParser = bodyParser.json() // body-parser 가 만들어내는 미들웨어가 들어옴 요청으로 들어오는 body 의 부분을 해석 app.use(cors()) app.use(jsonParser) // 전역에 jsonParser 설정. let message = { results: []}; app.get('/messages', (req, res) => { // doesnt need to be parsing. res.status(200).send(message); // console.log(message) }) app.post('/messages', jsonParser, (req, res) => { // why jsonParser? = > "POST" // console.log(req) message.results.push(req.body); res.status(201).send(JSON.stringify(req.body)); }) app.listen(3000)