반응형


파일을 서버의 폴더로 업로드하기





브라우저에서 파일 올리기 요청을 하면 서버에 설정해둔 경로로 파일을 업로드한다


이때 파일 업로드를 위해 사용되는 주 모듈은


1
2
3
var multer = require('multer');     //파일 업로드하기 위한 모듈
var fs = require('fs');             //파일 시스템
var cors = require('cors');         //다중 서버로 접속하게 해주는 기능을 제공, 다른 ip 로 다른서버에 접속
cs

이렇게 3개이다



아래 지정한 경로대로 서버에 업로드할 파일을 전송하게 된다



photo.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!DOCTYPE html>
 
<html>
<head>
    <meta charset="utf-8" />
    <title>upload file</title>
</head>
    <h1>upload file</h1
 
<form method="post" action="/process/photo" enctype="multipart/form-data">
    <table>
        <tr>
            <td><label>file</label></td>
            <td><input type="file" name="photo" /></td<!--photo 이 이름이 서버쪽으로 요청파라미터 이름으로 들어가게됨-->
        </tr>
    </table>
    <input type="submit" value="upload" name="summit" />
</form>
<body>
 
</body>
</html>





photo.html 실행시킨 모습







서버 nodejs 코드


서버코드인데 중간에 cors 를 사용한 부분이 있는데 이것은 웹페이지를 연서버가 있으면 그 서버로만 접속하게끔 되어 있는 보안 정책이 있는데 

파일 업로드하기 위해선 이것을  꼭 서버에만 접속해선 기능을 만들기 힘들수 있음으로 cors 를 상용해 이 정책을 우회한다


var cors = require('cors');         //다중 서버로 접속하게 해주는 기능을 제공, 다른 ip 로 다른서버에 접속

app.use(cors());                      //다중 접속을 위한 미들웨에



파일이 저장될 경로 세팅

1
app.use('/uploads',serveStatic(path.join(__dirname, 'uploads')));



웹은 기본적으로 '동일출저정책(Same Origin Policy, SOP)' 정책을  따른다.


이는 보안을 위한 기본정책으로, SOP는 하나의 출처(Origin)에서 로드된 문서나 스크립트가 다른 출처에 존재하는 리소스와 상호작용하지 못하도록 제약을 두는 것이다.


그런데, 간혹 이런 제약이 웹 응용프로그램을 만드는데 걸림돌이 되기도 한다.

Ajax 통신이 활발해 지고, 다른 사이트에 존재하는 Open API와 상호통신이 필요한 경우와 매쉬업(Mash-up)으로 새로운 2차 응용물을 개발하게 되면서.. 등등.. 이는 간혹 걸림돌이 된다.


근래 Node.JS로 서버를 만들고, Aptana Studio 자체 내장 웹서버로 몇 가지 테스트를 하고 있는데, 두 환경은 서로 다른 별도의 포트(Port)에서 웹을 동작시키기 때문에 여지없이 Cross Domain 문제가 발생한다.




호출하는 모든 웹 리소스를, Node.JS로부터 다운로드 받아서 실행하는 구조로 HTTP 서버를 구현하면 SOP 정책을 따를 수 있겠으나, 그렇지 못한 개발환경도 있을 터이고, 실제 서비스 환경에서는 더욱이 서로 다른 도메인(포트 포함)간 상호작용이 필요할 것이다.


SOP 정책을 우회하기 위해서는, 서버 측의 설정이 필요한데, 위 그림에서 친철히 안내하고 있는 것처럼 Access-Control-Allow-Origin 헤더, 즉 크로스 도메인으로 허용할 도메인 목록이 헤더로 제공되어야 한다.

이것을 CORS(Cross-Origin Resource Sharing)를 이용한 SOP 정책 우회라 한다.







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
var express = require('express');
var http = require('http');
var serveStatic = require('serve-static');      //특정 폴더의 파일들을 특정 패스로 접근할 수 있도록 열어주는 역할
var path = require('path');
var cookieParser = require('cookie-parser');
var expressSession = require('express-session');
 
var multer = require('multer');     //파일 업로드하기 위한 모듈
var fs = require('fs');             //파일 시스템
var cors = require('cors');         //다중 서버로 접속하게 해주는 기능을 제공, 다른 ip 로 다른서버에 접속
var app = express();      //express 서버 객체
 
 
app.set('port'3000);
app.use(serveStatic(path.join(__dirname, 'public')));
app.use('/uploads',serveStatic(path.join(__dirname, 'uploads')));
 
 
var bodyParser_post = require('body-parser');       //post 방식 파서
//post 방식 일경우 begin
//post 의 방식은 url 에 추가하는 방식이 아니고 body 라는 곳에 추가하여 전송하는 방식
app.use(bodyParser_post.urlencoded({ extended: false }));            // post 방식 세팅
app.use(bodyParser_post.json());                                     // json 사용 하는 경우의 세팅
//post 방식 일경우 end
 
 
 
//쿠키와 세션을 미들웨어로 등록한다
app.use(cookieParser());
 
//세션 환경 세팅
//세션은 서버쪽에 저장하는 것을 말하는데, 파일로 저장 할 수도 있고 레디스라고 하는 메모리DB등 다양한 저장소에 저장 할 수가 있는데
app.use(expressSession({
    secret: 'my key',           //이때의 옵션은 세션에 세이브 정보를 저장할때 할때 파일을 만들꺼냐 , 아니면 미리 만들어 놓을꺼냐 등에 대한 옵션들임
    resave: true,
    saveUninitialized: true
}));
 
 
 
 
//파일을 올리기위한 세팅 시작
 
 
//다중 접속을 위한 미들웨에
app.use(cors());
 
//파일 업로드를 위한 설정
var fileStorage =  multer.diskStorage(
    {
        destination: function (req,file, callback)
        {
            callback(null'uploads');      //목적지 폴더 지정 : 'uploads' 를 목적지로 정한다(이쪽으로 파일이 오게됨)
        },
        filename: function (req, file, callback)
        {
            //올린 파일명이 기존과 같으면 덮어씌워짐으로 시간을 기준으로 다른 파일로 저장되게끔 처리한다
   
            var extention = path.extname(file.originalname);
            var basename = path.basename(file.originalname, extention);        //확장자 .jpg 만 빠진 파일명을 얻어온다
            var fname = basename + Date.now() + extention;
            callback(null, fname);  
 
        }
 
    }
);
 
var upload = multer(
    {
        storage: fileStorage,
        limits:
            {
                files: 10,                      //10개까지
                fileSize: 1024 * 1024 * 1024    //한번 업로드 할때 최대 사이즈
            }
    }
);
 
//파일을 올리기위한 세팅 끝
//이제 이것을 갖고 라우터를 통해서 파일을 업로드 할수 있게끔 해야함
 
 
//라우트를 미들웨어에 등록하기 전에 라우터에 설정할 경로와 함수를 등록한다
//
//라우터를 사용 (특정 경로로 들어오는 요청에 대하여 함수를 수행 시킬 수가 있는 기능을 express 가 제공해 주는것)
var router = express.Router();
 
 
 
 
//upload.array : Accept an array of files, all with the name fieldName. 
//Optionally error out if more than maxCount files are uploaded.
//The array of files will be stored in req.files. 
//('photo',1) : photo 라고 지정한 파일이 있다면 1개를 전송하라는 의미
router.route('/process/photo').post(upload.array('photo',1),
    function (req, res)
    {
        console.log('/process/photo 함수가 호출됨');
        var files = req.files;
        if (files.length > 0)
        {
            console.dir(files[0]);
        }
        else
        {
            console.log('파일이 없음');
        }
 
 
        res.writeHead(200, { "Content-Type""text/html;characterset=utf8" });
        res.write('<h1>file upload complete</h1>');
        if (Array.isArray(files))
        {
            files.forEach(
                function (elem)
                {
                    res.write('<h1>' + elem.originalname + '</h1>');
                    res.write('<h1>' + elem.filename + '</h1>');
                    res.write('<h1>' + elem.mimetype + '</h1>');
                    res.end();
                      
                }
            );
        }
 
        
    }
);
 
 
//http://localhost:3000/process/product 이 주소로 치면 라우터를 통해 바로 여기로 올 수 있다
router.route('/process/product').get(
    function (req, res) {
        console.log('/process/product  라우팅 함수 실행');
 
        //세션정보는 req.session 에 들어 있다
        if (req.session.user)       //세션에 유저가 있다면
        {
            res.redirect('/product.html');
        }
        else {
            res.redirect('/login2.html');
 
        }
    }
);
 
router.route('/process/login').post(                      //설정된 쿠키정보를 본다
    function (req, res) {
        console.log('/process/login 라우팅 함수호출 됨');
 
        var paramID = req.body.id || req.query.id;
        var pw = req.body.passwords || req.query.passwords;
 
        if (req.session.user) {
            console.log('이미 로그인 되어 있음');
 
            res.writeHead(200, { "Content-Type""text/html;characterset=utf8" });
            res.write('<h1>already Login</h1>');
            res.write('[ID] : ' + paramID + ' [PW] : ' + pw);
            res.write('<a href="/process/product">Move</a>');
            res.end();
 
        } else {
            req.session.user =
                {
                    id: paramID,
                    pw: pw,
                    name'UsersNames!!!!!',
                    authorized: true
                };
            res.writeHead(200, { "Content-Type""text/html;characterset=utf8" });
            res.write('<h1>Login Success</h1>');
            res.write('[ID] : ' + paramID + ' [PW] : ' + pw);
            res.write('<a href="/process/product">Move</a>');
            res.end();
        }
    }
);
 
router.route('/process/logout').get(                      //설정된 쿠키정보를 본다
    function (req, res) {
        console.log('/process/loginout 라우팅 함수호출 됨');
 
        if (req.session.user) {
            console.log('로그아웃 처리');
            req.session.destroy(
                function (err) {
                    if (err) {
                        console.log('세션 삭제시 에러');
                        return;
                    }
                    console.log('세션 삭제 성공');
                    //파일 지정시 제일 앞에 / 를 붙여야 root 즉 public 안에서부터 찾게 된다
                    res.redirect('/Login2.html');
                }
            );          //세션정보 삭제
 
        } else {
            console.log('로긴 안되어 있음');
            res.redirect('/Login2.html');
        }
 
 
 
    }
);
 
 
 
//라우터 미들웨어 등록하는 구간에서는 라우터를 모두  등록한 이후에 다른 것을 세팅한다
//그렇지 않으면 순서상 라우터 이외에 다른것이 먼저 실행될 수 있다
app.use('/', router);       //라우트 미들웨어를 등록한다
 
 
app.all('*',
    function (req, res) {
        res.status(404).send('<h1> 요청 페이지 없음 </h1>');
    }
);
 
//웹서버를 app 기반으로 생성
var appServer = http.createServer(app);
appServer.listen(app.get('port'),
    function () {
        console.log('express 웹서버 실행' + app.get('port'));
    }
);
 





파일을 올리고 나면 다음처럼 파일이 uploads 폴더에 저장되어 있는 것을 확인할 수 있다







정책 일부 ref : http://m.mkexdev.net/339

반응형

+ Recent posts