Node 수동 정적 리소스 서버
배경
서버 지식을 배우려면 서버에 파일을 마운트해야 상응하는 파일에 접근할 수 있습니다.로컬 개발을 할 때, 우리는 같은 랜에서 같은 서버 주소를 통해 같은 파일에 접근할 수 있도록 자주 파일을 서버에 저장합니다. 예를 들어 우리는 xampp를 사용하고sulime의 플러그인sublime-server를 사용합니다.이 글은 node를 통해 정적 자원 서버를 손으로 써서 모든 폴더를 루트 디렉터리로 정의하고 해당하는 파일에 접근하여anywhere is yourstatic-server에 도달할 수 있도록 합니다.
주요 구현 기능
Useage
//install
$ npm i st-server -g
//forhelp
$ st-server -h
//start
$ st-server
// or with port
$ st-server -p 8800
// or with hostname
$ st-server -o localhost -p 8888
// or with folder
$ st-server -d /
// full parameters
$ st-server -d / -p 9900 -o localhost
그 중에서 세 개의 매개 변수를 설정할 수 있습니다. - d는 당신이 방문할 루트 디렉터리를 대표하고, - p는 포트 번호를 대표합니다. (현재는 같은 포트 번호를 여러 번 열 수 없습니다. 이전의 프로세스를 수동으로 죽여야 합니다.) - o는hostname을 대표합니다.모든 원본 코드가github에 업로드되었습니다.
원본 분석
class StaticServer{
constructor(argv){
this.config = Object.assign({},config,argv);
this.compileTpl = compileTpl();
}
startServer(){
let server = http.createServer();
server.on('request',this.request.bind(this));
server.listen(this.config.port,()=>{
let serverUrl = `http://${this.config.host}:${this.config.port}`;
debug(` , ${chalk.green(serverUrl)}`);
})
}
}
async request(req,res){
let {pathname} = url.parse(req.url);
if(pathname == '/favicon.ico'){
return this.sendError('NOT FOUND',req,res);
}
//
let filePath = path.join(this.config.root,pathname);
let statObj = await fsStat(filePath);
if(statObj.isDirectory()){//
let files = await readDir(filePath);
let isHasIndexHtml = false;
files = files.map(file=>{
if(file.indexOf('index.html')>-1){
isHasIndexHtml = true;
}
return {
name:file,
url:path.join(pathname,file)
}
})
if(isHasIndexHtml){
let statObjN = await fsStat(filePath+'/index.html');
return this.sendFile(req,res,filePath+'/index.html',statObjN);
}
let resHtml = this.compileTpl({
title:filePath,
files
})
res.setHeader('Content-Type','text/html');
res.end(resHtml);
}else{
this.sendFile(req,res,filePath,statObj);
}
}
sendFile(req,res,filePath,statObj){
//
if (this.getFileFromCache(req, res, statObj)) return; // ,
res.setHeader('Content-Type',mime.getType(filePath)+';charset=utf-8');
let encoding = this.getEncoding(req,res);
//
let rs = this.getPartStream(req,res,filePath,statObj);
if(encoding){
rs.pipe(encoding).pipe(res);
}else{
rs.pipe(res);
}
}
sendFile 방법은 브라우저에 내용을 출력하는 방법입니다. 주로 다음과 같은 몇 가지 중요한 점을 포함합니다.
getFileFromCache(req,res,statObj){
let ifModifiedSince = req.headers['if-modified-since'];
let isNoneMatch = req.headers['if-none-match'];
res.setHeader('Cache-Control','private,max-age=60');
res.setHeader('Expires',new Date(Date.now() + 60*1000).toUTCString());
let etag = crypto.createHash('sha1').update(statObj.ctime.toUTCString() + statObj.size).digest('hex');
let lastModified = statObj.ctime.toGMTString();
res.setHeader('ETag', etag);
res.setHeader('Last-Modified', lastModified);
if (isNoneMatch && isNoneMatch != etag) {
return false;
}
if (ifModifiedSince && ifModifiedSince != lastModified) {
return false;
}
if (isNoneMatch || ifModifiedSince) {
res.statusCode = 304;
res.end('');
return true;
} else {
return false;
}
}
여기에서 우리는 Last-Modified, ETag를 통해 협상 캐시를 실현하고, Cache-Control, Expires를 통해 강제 캐시를 실현하며, 모든 캐시 조건이 성립될 때만 효력이 발생한다.Last-Modified 원리는 파일의 수정 시간을 통해 파일이 수정되었는지, ETag는 파일 내용의 암호화를 통해 수정되었는지 판단하는 것이다.Cache-Control, Expire는 시간을 통해 완만합니다.
getEncoding(req,res){
let acceptEncoding = req.headers['accept-encoding'];
if(acceptEncoding.match(/\bgzip\b/)){
res.setHeader('Content-Encoding','gzip');
return zlib.createGzip();
}else if(acceptEncoding.match(/\bdeflate\b/)){
res.setHeader('Conetnt-Encoding','deflate');
return zlib.createDeflate();
}else{
return null;
}
}
getPartStream(req,res,filePath,statObj){
let start = 0;
let end = statObj.size -1;
let range = req.headers['range'];
if(range){
res.setHeader('Accept-Range','bytes');
res.statusCode = 206;
let result = range.match(/bytes=(\d*)-(\d*)/);
if(result){
start = isNaN(result[1]) ? start : parseInt(result[1]);
end = isNaN(result[2]) ? end : parseInt(result[2]) - 1;
}
}
return fs.createReadStream(filePath,{
start,end
})
}
#! /usr/bin/env node
let yargs = require('yargs');
let argv = yargs.option('d', {
alias: 'root',
demand: 'false',
type: 'string',
default: process.cwd(),
description: ' '
}).option('o', {
alias: 'host',
demand: 'false',
default: 'localhost',
type: 'string',
description: ' '
}).option('p', {
alias: 'port',
demand: 'false',
type: 'number',
default: 8800,
description: ' '
})
.usage('st-server [options]')
.example(
'st-server -d / -p 9900 -o localhost', ' 9900 '
).help('h').argv;
let path = require('path');
let {
spawn
} = require('child_process');
let p1 = spawn('node', ['www.js', JSON.stringify(argv)], {
cwd: __dirname
});
p1.unref();
process.exit(0);
참고
anywhere
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.