서버전송 이벤트

            
                
            
        
            
                let nick= prompt("Enter your nickname")
                let input= document.getElementById("input")
                input.focus()

                let chat= new EventSource("/chat");
                chat.addEventListener("chat", event => { // 채팅 메시지가 도착하면;
                    let div= document.createElement("div")
                    div.append(event.data) // 텍스트 메시지를 추가한다
                    input.before(div) // 입력필드 앞에 div를 추가한다
                    input.scrollIntoView() // 입력 필드가 보이게 한다
                });

                // 사용자의 메시지를 서버로 보낸다
                input.addEventListener("change", ()=>{ // 사용자가 Enter 키를 누르면;
                    fetch("/chat", {
                        method: "POST",
                        body: nick + ": " + input.value
                    }).catch(e => console.error) // 응답은 무시하고, 에러는 기록한다

                    input.value = "";
                });
            
        
            
                /* 아주 단순한 익명 채팅방 서버: chatServer.js */
                // /chat에 새로운 메시지를 POST로 보내거나 GET으로 text/event-stream 메시지를 받는다
                // /에 GET 요청을 보내면 클라이언트 사이드 채팅 UI가 포함된 단순한 HTML 파일을 받는다
                const http= require("http")
                const fs= require("fs")
                const url= require("url")


                const clientHTML= fs.readFileSync("chatClient.html") // 채팅 클라이언트 html 파일
                let clients= [] // 이벤트를 보낼 ServerResponse 객체 배열

                let server= new http.Server() // http 서버 생성
                server.listen(8080)

                server.on("request", (request, response) => { // 서버가 요청을 받으면;
                    let pathname= url.parse(request.url).pathname

                    if (pathname === "/") { // 요청이 "/"라면; 클라이언트 사이드 채팅 UI를 전송한다
                        response.writeHead(200, {"Content-Type": "text/html"}).end(clientHTML);
                    } else if (pathname !== "/chat" || (request.method !== "GET" && request.method !== "POST")) {
                        response.writeHead(404).end()
                    } else if (request.method === "GET") { // /chat에 GET 요청이 들어왔다면;
                        acceptNewClient(request, response) // 클라이언트가 연결한다
                    } else { // 아니라면;
                        broadcastNewMessage(request, response) // 새로운 메시지를 보내는 POST 요청이다
                    }
                });

                // 클라이언트가 새로운 EventSource 객체를 생성할 때,
                // 또는 EventSource 객체가 자동으로 다시 연결될 때 생성되는 /chat 엔드포인트의 GET 요청을 처리한다
                function acceptNewClient(request, response) {
                    clients.push(response) // 나중에 메시지를 보낼 수 있도록 응답 객체를 기억한다

                    request.connection.on("end", () => { // 클라이언트가 연결을 끊으면;
                        clients.splice(clients.indexOf(response), 1)
                        response.end() // 해당 클라이언트의 응답 객체를 제거한다
                    });

                    // 헤더를 설정하고 이 클라이언트에 초기 채팅 이벤트를 전송한다
                    response.writeHead(200, {
                        "Content-Type": "text/event-stream",
                        "Connection": "keep-alive",
                        "Cache-Control": "no-cache"
                    });

                    response.write("event: chat\ndata: Connected\n\n")
                    // 서버 전송 이벤트는 연결을 계속 유지해두어야 하므로, response.end()는 호출하지 않는다!
                }

                // 이 함수는 사용자가 새로운 메시지를 보내는 /chat 엔드포인트에 대한 POST 요청의 응답으로 호출된다
                async function broadcastNewMessage(request, response) {
                    // 먼저 요청 바디를 읽어 사용자의 메시지를 가져온다
                    request.setEncoding("utf8")

                    let body= ""
                    for await (let chunk of request) {
                        body += chunk
                    }

                    response.writeHead(200).end() // 바디를 읽으면 빈 응답을 보내고 연결을 닫는다

                    // 메시지를 text/event-stream 형식으로 바꾸고, 각 행 앞에 "data: "를 붙인다
                    let message= "data: " + body.replace("\n", "\ndata: ");

                    // 메시지 데이터 앞에 채팅 이벤트임을 뜻하는 전치사를 붙이고 뉴라인 두개를 이어붙여 이벤트가 끝났음을 알린다
                    let event= `event: chat\n${message}\n\n`;

                    // 연결된 클라이언트 전체에 이 이벤트를 전송한다
                    clients.forEach(client => client.write(event));
                }