2017년 11월 24일 금요일

Chapter8. HTTP 서버



학습 목표


  1. HTTP 모듈을 이용해서 서버를 작성할 수 있습니다.
  2. HTTP 요청을 분석하는 코드를 작성할 수 있습니다.
  3. HTTP 응답 메시지를 작성하는 코드를 작성할 수 있습니다.
  4. 정적 파일 요청과 서비스 제공하는 서버를 작성할 수 있습니다.


1. HTTP 서버

◎ HTTP 서버 구동 코드
var http = require('http');
var server = http.createServer(function(req, res) {
    res.end('Hello World');
}).listen(3000);

2. HTTP 요청

◎ HTTP 요청
  • 클라이언트 요청 분석
  • request 이벤트 리스너의 파라미터
  • req : IncomingMessage
    var server = http.createServer(function(req, res) {} )
▷ 클라이언트 요청 분석
▷ IncomingMessage
  • message.url : 요청 url, 경로와 쿼리 문자열
  • message.method : 요청 메소드
  • message.headers : 요청 메소드의 헤더
  • message(streamable) : 요청 메시지 바디
▷ 요청 URL 경로와 쿼리 문자열 분석
▷ URL 분석하기 : URL 모듈
var url = require('url');
url.parse(req.url, true);

▷ 요청 메시지 헤더 분석
▷ 헤더 정보 : request.header
var headers = request.headers;
headers.host;
headers.content-type;
headers.user-agent;
. . .

▷ 요청 메시지 바디 분석
  • IncomingMessage의 data 이벤트 사용
  • POST 요청을 다루는 장에서 다룬다.
◎ HTTP 요청 출력
▷ 요청 내용 콘솔에 출력하기
var server = http.createServer(function(req, res) {
    console.log('HTTP Method : ' + req.method);
    console.log('HTTP URL : ' + req.url);
    console.log('== HEADERS ==');
    console.log(req.headers);

    res.end('Hello Node.js');
});

3. HTTP 응답

◎ 응답 메시지

  • 응답 메시지 : http.ServerResponse
  • 상태 코드와 상태 메시지
  • 응답 메시지 헤더
  • 응답 메시지 바디
▷ 메시지 상태
response.statusCode
response.statusMessage

▷ 메시지 헤더
response.writeHead(statusCode[, statusMessage][, headers])
response.removeHeader(name)
response.getHeader(name)
response.setHeader(name, value)

▷ 메시지 바디
response.end([data][, endcoding][, callback])
response.write(chunk[, encoding][, callback])

▷ HTTP 상태 코드와 메시지
// 200 OK
response.statusCode = 200;
response.statusMessage = 'OK';

// 404 Error
response.statusCode = 404;
response.statusMessage = 'Not found';

▷ 응답 메시지 헤더

▷ 응답 코드, 메시지 헤더 작성 함수 : writeHead
res.writeHead(200, {'Content-Length': body.length,
                          'Content-Type': 'text/plain'});

▷ 헤더 작성하기 : setHeader
res.setHeader("Content-Type", "text/html");
res.setHeader("Content-Length", body.length);

▷ 응답 메시지 바디
▷ 응답 메시지 종료
response.write(chunk[, endcoding][, callback])
response.end()

▷ 응답 메시지 작성 시 주의

▷ 응답 메시지 종료 - 클라이언트 대기 - timeout
http.createServer(function(req, res) {
    res.write('Hello Node.js');
    res.end(); // 응답 메시지를 완료시켜주어야 한다.
});

▷ 메시지 헤더는 메시지 바디 작성 전에
res.write('Hello World');
// 바디를 작성한 이후에 헤더를 작성하면 에러가 발생한다.
res.setHeader('Conent-Type', 'text/plain');

4. HTTP 서버 작성

◎ 정적 파일 요청
▷ 정적인 컨텐츠(이미지, html, 음악 등) 요청
  • 미리 작성된 파일로 응답
▷ 요청 예
  • http://myServer.com/image/cat.jpg
  • http://myservice.net/music/sing.mp3
▷ 요청 경로
  • req.url
▷ 요청 경로 분석
  • path 모듈
▷ 정적 파일 요청 : 응답
  • 정적 파일 찾기
  • 파일 로딩, 응답
▷ fs 모듈
  • fs.readFile(FILEPATH, CALLBACK);
▷ 응답 메시지에 파일 내용 쓰기
  • res.write();
  • res.end();
▷ 정적 파일 요청에 대한 응답
fs.access(path, fs.F_OK, function(exist) {
    fs.readFile(path, function(err, data) {
        res.end(data);
    });
});

◎ 정적 파일 요청
  • 정적 파일 요청에 대한 응답
  • 정적 파일 체크
  • 상태 코드
  • 컨텐츠 타입
▷ 파일이 없으면?

▷ 404 에러 처리 코드
fs.access(path, fs.R_OK, function(err) {
    // 접근 불가능 시 404 에러
    if( err ) {
        res.statusCode = 404;
        res.end('Not Found');
        return;
    }
}

▷ 정적 파일 응답
fs.access(path, fs.F_OK, function(err) {
    if( err ) {
        res.statusCode = 404;
        res.end('Not found');
        return;
    }
    fs.readFile(path, function(err, data) {
        res.statusCode = 200;
        res.setHeader('Content-type', 'image/jpg');    // 이미지라면
        res.end(data);
    });
});

▷ 스트림 파이프
  • 입력 스트림 : fs.createReadStream()
  • 출력 스트림 : res
    fs.createReadStream(path).pipe(res);
▷ 파미콘 : 웹 사이트의 아이콘 이미지
▷ 파비콘 요청
  • GET /favicon.ico
▷ 파비콘 응답 코드
if( request.url == '/favicon.ico' ) {
    // 파비콘 처리
    return;
}

▷ 컨텐츠 타입
var server = http.createServer(function(req, res) {
    if(req.url == '/favicon.ico') {}
    else if(req.url == '/image.png' ) {
        res.writeHeader(200, {'Content-Type':'image/png'});
        fs.read...
    }
    else if(req.url == '/music.mp3') {
        res.writeHeader(200, {'Content-Type':'audio/mp3'});
        fs.createReadStrea...
    }
    else if(req.url == '/movie.mp4') {
        res.writeHead(200, {'Content-Type':'video/mp4'});
        fs.createReadStream...
    }
});

◎ 정적 파일 서비스
▷ 요청 URL의 경로를 실제 파일 경로 매핑
  • myServier.com/resource/image.png -> ./resources/image.png
  • myServier.com/resource/audio.mp3 -> ./resources/audio.mp3
▷ 요청 url에서 경로 생성
URL로부터 파일의 패스 정보를 가져와서 바로 파일에 대한 경로를 만들어 줄 수 있다.
파일을 찾고 파일에 대한 읽기위한 경로를 만드는 과정이 단순해짐.

var pathUtil = require('path');
var path= __dirname + pathUtil.sep + 'resources' + req.url;

◎ 웹 페이지 서비스
▷ 요청
  • 인덱스 요청
  • 파비콘 요청
  • JS와 css요청
  • 이미지 요청 : <img>
▷ 서비스 용 html
<html>
<link rel="stylesheet" type="text/css" href='public/style.css'>
<body>
    <h1>Hello Kitty</h1>
    <img src='image/cat.jpg'>
</body>
</html> 

html요청
css 요청
image 요청
파비콘 요청 에 대한 응답 처리를 모두 해주저야 한다.

▷ 서버 코드
var server = http.createServer(function(req, res) {
    if(req.url == '/favicon.ico') {
        // 파비콘 응답
    }
    else if(req.url == '/') {
        // 기본 페이지 : index.html
        fs.createReadStream('./public/index.html').pipe(res);
    }
    else {
        var path = __dirname + req.url;
    }
})

◎ 서비스
▷ 서비스
▷ URL 쿼리 문자열 : 합계 구하기
http://127.0.0.1:3000/count?start=1&end=10

▷ 서버 코드
// URL 분석 : 쿼리 문자열
var parsed = url.parse(request.url, true);
var query = parsed.query;

// start와 end
var start = parseInt(query.start);
var end = parseInt(query.end);

if(입력값 오류) {
    response.statusCode = 404;
    response.end('Wrong Parameter');
}
else {
    // 합계 구하기
    response.statusCode = 200;
    response.end('Result : ' + result);
}

학습 정리

◎ 지금까지 'HTTP 서버'에 대해 살펴보았습니다.
  • HTTP 요청
    클라이언트의 HTTP 요청을 분석했습니다.
  • HTTP 응답
    클라이언트에게 HTTP 응답 메시지를 작성하고 전송하는 방법을 알아봤습니다.
  • HTTP 서버
    다양한 형태의 HTTP 서버 작성 방법을 알아봤습니다.
   



댓글 없음: