본문 바로가기
멀티캠퍼스 풀스택 과정/백엔드

[Node.js] 5. 클라이언트 요청으로 이미지, 동영상 파일을 읽기(Mime과 stream)

by 이쟝 2022. 3. 31.

1. 화면에 보일 HTML(home.html) 파일 생성(이미지 읽기)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>home.html</title>
    <style>
        img{width:300px; height:300px;}
    </style>
</head>
<body>
    <h1>노드를 이용한 홈페이지</h1>
    <a href=""><img src="./img/park6.png"/></a> <!--나중에 맵핑-->
    <img src="./img/dog3.jpg"/>
    <img src="./img/dog4.jpg"/>
    <img src="./img/dog5.jpg"/>
</body>
</html>

2. Mime-Type을 사용해 이미지를 보이게 하기

Mime(Multipurpose Internet Mail Extensions)

  • 메시지의 내용이 어떤 형식인지 알려주기 위해 정의한 것 
  • mime 모듈을 사용하기 위해서 cmd창에 npm 명령어를 이용해 추가한 뒤에 객체 생성한다.
    • npm install mime@2  (@2는 .2버전이라는 뜻)
  • 아래의 값을 Content-Type을 통해서 헤더 값을 적절한 MIME-Type 값으로 설정하면 된다.

 

Content-Type  설명
text/plain 일반 텍스트 문서
text/html HTML 문서
text/css css 문서
text/xml xml 문서
image/jpeg, imapge/png jpeg파일 png 파일
video/mpeg, audio/mp3 mpeg 비디오 파일, mp3 파일
application/zip zip 압축파일

1. home.html 파일의 내용을 읽어 response할 파일 생성(node11_html_img_response.js)

let http = new require('http');
let fs = new require('fs');

let server = http.createServer(function(request, response){
	let addr = request.url 
    console.log(addr);  // (1)
    
    if(addr=='/home'){  // (2)
    	fs.readFile(__dirname+'/home.html','utf-8',function(e,d){
        	if(e){ // home.html 파일 읽기 실패
            	console.log("home.html 파일 읽기 실패 + e);
            }else{ // home.html 파일 읽기 성공
            	response.writeHead(200, {'Content-Type':'text/html;charset='utf-8'});
                response.end(d);
            }
        });
    }
});

server.listen(10007, function(){
	console.log('servert start! http://127.0.0.1:10007/home'); // (3)
});

(1) 파일을 읽기 위해서 절대주소를 알아야 하기 때문에 콘솔에 찍어본다.

(2) 요청이 들어오면(주소가 /home(home.html)로 접속할 경우에만) readFile() 메서드로 파일을 읽는다.

  • 파일을 모두 읽으면 콜백 함수 안의 d 로 파일 내용이 전달된다. 
  • 함수 안의 writeHead와 end메서드를 통해 파일 내용을 클라이언트로 전달한다. 
  • 현재는 이미지 값이 아닌 html 형식만 넘긴다. 

(3) 링크를 클릭하면 home html 파일에 접속되어야 함

 

console.log(request.url) 때문에 서버 주소로 접속하면 /home, /img/park6.png, /img/dog3.jpg..가 콘솔에 찍힌다. 

2. 파일의 확장자를 읽기 위해서 mime 모듈을 다운 받는다.

mime 모듈이 추가되었다.

3. 파일의 주소가 /img로 시작할 경우 response 한다. 

let http = new require('http');
let fs = new require('fs');
let mime = new require('Mime'); (1)

let server = http.createServer(function(request, response){

    let addr = request.url;
    
    if(addr=='/home'){
        fs.readFile(__dirname+'/home.html','utf-8',function(e, d){
            if(e){ // 파일 읽기 에러
                console.log("home.html파일 읽기 실패" + e);
            }else{ /// 파일 읽기 성공
                response.writeHead(200, {'Content-Type':'text/html;charset=utf-8'});
                response.end(d);
            }
        });
    }
    else if(addr.indexOf('/img') == 0){ // (2)
        let mimeType = mime.getType(addr.substring(1)); // (3)
        console.log(mimeType);

        fs.readFile(__dirname+addr, function(error, imgData){ // (4)
            if(!error){
                response.writeHead(200,{'Content-Type':'mimeType'});
                response.end(imgData);
            }
        });
    }
});

server.listen(10007, function(){
    console.log("server start! http://127.0.0.1:10007/home"); 
});

(1) mime을 사용하기 위해 mime 객체 생성(mime의 첫글자는 대문자로 한다.)

(2) /img로 시작하는 경우에만 이미지 파일로 인식하고 함수를 실행한다. 이미지일 경우에는 0 아니면 -1로 구분한다. 

  • 프로젝트 안에 img 폴더를 생성했기 때문에 img안에 이미지 파일이 있다. 

(3) 파일의 확장자(png, jpeg..)를 구하기 위해서 getType( )메서드를 사용해서 mime의 Type을 구한다. 

  • /img/dog2.jpg일 때 img 앞에 /을 생략한다. (substring으로 자르기)

(4) readFile( )로 이미지 파일을 읽는다. 매개변수로 파일 경로+파일명(request.url)과 콜백 함수

  • 파일을 모두 읽으면 콜백 함수 안의 imgData로 파일 내용이 전달된다. 
  • 함수 안의 writeHead와 end메서드를 통해 파일 내용을 클라이언트로 전달한다. 
  • Content-Type이 mimeType으로 되어서 여러 이미지 파일 형식을 넘길 수 있다.  

 

console.log(mineType) 때문에 서버 주소로 접속하면 각 이미지 파일의 종류명(png, jpeg)이 콘솔에 찍힌다.

4. home.html에 연결되는 서브페이지 생성(subpage.html)

// home.html
    <a href="/subpage"><img src="./img/park6.png"/></a>

subpage.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>subpage.html</title>
</head>
<body>
    <h1>서브페이지</h1>
    <img src="/img/dog3.jpg"/>
</body>
</html>

5. 서브페이지 요청을 받으면 응답하는 코드를 위에 파일에 이어서 작성한다.(node11_html_image_response.js) 

	}else if(addr=='/subpage'){ //(1)
        fs.readFile(__dirname+"/subpage.html","utf-8", function(error, data){ //(2)
            if(!error){
                response.writeHead(200, {"Content-Type":"text/html;charset=utf-8"});
                response.end(data);
            }
        });
    }

(1) 파일의 경로가 /subpage가 들어가는 경우에만 인식하고 함수를 실행한다. 

(2) readFile( )로 이미지 파일을 읽는다. 매개변수로 파일 경로+파일명(request.url)과 콜백 함수

  • 파일을 모두 읽으면 콜백 함수 안의 data 로 파일 내용이 전달된다. 
  • 함수 안의 writeHead와 end메서드를 통해 파일 내용을 클라이언트로 전달한다. 
  • Content-Type이 html 형식이라서 html을 표시할 수 있다. 

home.html에서 첫 번째 그림을 클릭하면 subpage.html로 넘어간다. (이미지 맵핑은 이미 위에서 했기 때문에 없어도 가능!)

 


4. 동영상 파일 처리하기 (stream)

stream: 스트리밍 데이터로 작업하기 위한 추상적인 인터페이스
즉 어디로 가는지, 어디로 나왔는지 상관없이 통일된 방식으로 데이터를 다루기 위한 가상의 개념

 

Stream 타입 종류

Readable  읽을 수 있는 스트림(ex fs.createReadStream( ))
Writable 쓸 수 있는 스트림(ex fs.createWriteStream( ))

1. movie 폴더에 mp4(동영상) 파일을 넣고, 동영상파일을 보여줄 movie_play.html 파일 생성

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>동영상 스트리밍 처리하기</title>
</head>
<body>
    <h1>노드에서 동영상 스트리밍 실행</h1>
    <video width="300" controls>
        <source src="./movie/cat.mp4"/>
    </video>
    <br/>
    <img src="./img/dog5.jpg"/>
</body>
</html>

이 html에서는 두가지 종류의 파일형식을 읽을 수 있어야 한다.(mp4와 img 형식)

2. 동영상과 이미지파일을 읽는 js 파일 생성(node12_html_movie_response.js)

let http = new require('http');
let fs = new require('fs');
let mine = new require('Mime');

let server = http.createServer(function(request,response){
    let mapping = request.url;  // '/ 이후부터 들어오는 주소'
    // html 문서 보내기
    // img 보내기
    // video 보내기
});

server.listen(10008, function(){
    console.log('server start http:127.0.0.1:10008');
});

1. html 문서 보내기와 img 보내기

let http = new require('http');
let fs = new require('fs');
let mime = new require('Mime');

let server = http.createServer(function(request,response){
    let mapping = request.url;  // '/ 이후부터 들어오는 주소'

    // html 문서 보내기
    if(mapping=='/'){
        fs.readFile(__dirname+'/movie_play.html','utf-8',function(error, htmlData){
            if(!error){
                response.writeHead(200, {'Content-Type':'text/html;charset=utf-8'});
                response.end(htmlData);
            }
        });   
    }
    // img 보내기
    else if(mapping.indexOf('/img')==0){ 
        mimeType = mime.getType(mapping.substring(1)); // /img/dog4.jpg에서 -> img/dog4.jpg만 자겨온다. 

        fs.readFile(__dirname+mapping, function(err, imgData){
            if(!err){
                response.writeHead(200, {'Content-Type':'mimeType'});
                response.end(imgData);
            }
        });
    }
    // video 보내기

});

server.listen(10008, function(){
    console.log('server start http://127.0.0.1:10008');
});

3. 동영상 파일 보내기(스트리밍처리)

동영상은 파일이 커서 스트리밍 처리로 전송한다.

    // video 보내기
    else if(mapping.indexOf('/movie')==0){
        
        let stream = fs.createReadStream(mapping.substring(1)); // (1)

        // (2)
        let cnt = 1;
        stream.on('data', function(movieData){
            response.end(movieData);
            console.log(cnt++ + '번째 전송 됨' + movieData.length);
        });

        // (2)
        stream.on('end', function(){
            response.end();
            console.log('stream end!');
        });

        //(2)
        stream.on('error',function(){
            response.end();
            console.log('stream error!');
        });
    }

(1) 동영상 스트리밍 읽기 처리를 위해 객체를 생성한다. 맵핑주소는 img와 동일하게 한다.

(2) 스트리밍 처리를 하기 위해서 여러번 데이터를 전송해야 하는데 이벤트를 이용해 처리한다.

  • data 이벤트 : 데이터가 read된 경우 호출되는 이벤트 
  • end 이벤트 : 데이터가 read의 마지막일 떄 호출되는 이벤트
  • error 이벤트 : 데이터가 read 될 때 에러 발생 시 호출되는 이벤트