Node.js를 사용하여 정적 서버를 구현하는 방법

亚连
풀어 주다: 2018-06-02 14:55:24
원래의
1355명이 탐색했습니다.

이 글은 Node.js 정적 서버의 구현 방법을 주로 소개합니다. 매우 훌륭하고 참고할 만한 가치가 있습니다. 도움이 필요한 친구들이 참고할 수 있습니다.

URL을 입력하면 이 URL이 다음의 리소스(파일)에 해당할 수 있습니다. 서버)는 디렉토리에 해당할 수도 있습니다. 따라서 서버는 이 URL을 분석하고 상황에 따라 다른 작업을 수행합니다. 이 URL이 파일에 해당하면 서버는 파일을 반환합니다. 이 URL이 폴더에 해당하는 경우 서버는 이 폴더에 포함된 모든 하위 파일/하위 폴더 목록을 반환합니다. 위의 내용은 정적 서버가 주로 수행하는 작업입니다.

그러나 실제 상황은 그렇게 간단하지 않습니다. 우리가 얻은 URL이 잘못되었거나, 해당 파일이나 폴더가 전혀 존재하지 않거나, 일부 파일과 폴더가 시스템에 의해 보호되어 있을 수 있습니다. 클라이언트가 알기를 원하지 않습니다. 그러므로 우리는 이러한 특별한 상황에 대해 몇 가지 다른 반환과 프롬프트를 만들어야 합니다.

게다가 실제로 파일을 반환하기 전에 고객과 몇 가지 협상을 진행해야 합니다. 다양한 브라우저에 대해 다양한 반환 처리를 수행하려면 클라이언트가 수용할 수 있는 언어 유형, 인코딩 방법 등을 알아야 합니다. 클라이언트가 데이터를 더 잘 수신할 수 있도록 반환된 파일에 대한 몇 가지 추가 정보를 클라이언트에게 알려야 합니다. 파일을 캐시해야 하며 어떻게 캐시해야 합니까? 파일이 압축되어 있나요? 압축을 어떻게 풀어야 하나요? 잠깐...

이제 우리는 정적 서버가 주로 하는 거의 모든 일에 대해 사전적으로 이해했습니다. 이제 구성 파일

서버를 시작하려면 서버가 시작될 때 포트 번호를 알아야 합니다. 그리고 정적 서버의 작업 디렉터리

static-server/
|
| - bin/
| | - start # 批处理文件
|  
|
| - src/
| | - App.js # main文件
| | - Config.js # 默认配置
|
|
·- package.json
로그인 후 복사

전체 프레임워크

Attentionevent 함수 이것은 기본적으로 바인딩된 개체(여기서는 소규모 서버)를 가리키며, 다음과 같이 수정됩니다. 콜백 함수에서 서버 아래의 메소드를 호출하기 위해 대형 개체 서버.

let config = {
 host:'localhost' //提升用
 ,port:8080 //服务器启动时候的默认端口号
 ,path:path.resolve(__dirname,'..','test-dir') //静态服务器启动时默认的工作目录
}
로그인 후 복사

요청 요청 처리URL의 경로 이름을 가져와 서버의 로컬 작업 루트 디렉터리 주소와 연결하고 파일 이름을 반환합니다. 파일이거나 폴더입니다

파일 폴더입니다. readdir 메소드를 사용하여 폴더 아래의 목록을 반환하고, 목록을 객체 배열로 래핑한 다음, 핸들바를 사용하여 배열 데이터를 템플릿으로 컴파일하고 마지막으로 반환합니다. 템플릿은 파일이고 req, res, statObj 및 filepath는 sendFile로 전달된 다음 처리를 위해 sendFile로 전달됩니다

class Server(){
 constructor(options){
  /* === 合并配置参数 === */
  this.config = Object.assign({},config,options)
 }
 start(){
  /* === 启动http服务 === */
  let server = http.createServer();
  server.on('request',this.request.bind(this)); 
  server.listen(this.config.port,()=>{
   let url = `${this.config.host}:${this.config.port}`;
   console.log(`server started at ${chalk.green(url)}`)
  })
 }
 async request(req,res){
  /* === 处理客户端请求,决定响应信息 === */
  // try
  //如果是文件夹 -> 显示子文件、文件夹列表
  //如果是文件 -> sendFile()
  // catch
  //出错 -> sendError()
 }
 sendFile(){
  //对要返回的文件进行预处理并发送文件
 }
 handleCache(){
  //获取和设置缓存相关信息
 }
 getEncoding(){
  //获取和设置编码相关信息
 }
 getStream(){
  //获取和设置分块传输相关信息
 }
 sendError(){
  //错误提示
 }
}
module.exports = Server;
로그인 후 복사

[팁] 요청 방법을 비동기로 만들겠습니다. , 동기 코드 작성과 같은 비동기 방식을 작성할 수 있도록

sendFile

캐싱, 인코딩, 분할 전송 등의 기능이 포함됩니다.

async request(req,res){
 let pathname = url.parse(req.url);
 if(pathname == '/favicon.ico') return;
 let filepath = path.join(this.config.root,pathname);
 try{
  let statObj = await stat(filepath);
  if(statObj.isDirectory()){
   let files = awaity readdir(filepath);
   files.map(file=>{
    name:file
    ,path:path.join(pathname,file)
   });
   // 让handlebar 拿着数去编译模板
   let html = this.list({
    title:pathname
    ,files
   })
   res.setHeader('Content-Type','text/html');
   res.end(html);
  }else{
   this.sendFile(req,res,filepath,statObj);
  }
 }catch(e){
  this.sendError(e,req,res);
 }
}
로그인 후 복사

handleCache

처리 시 주의할 사항 캐시는 강제 캐시와 비교 캐시로 나누어지며, 강제 캐시의 우선순위가 상대 캐시보다 높습니다. 즉, 강제 캐시가 적용되면 상대 캐시가 사용되지 않으며 서버는 요청을 시작하지 않습니다. 그러나 강제 캐시가 실패하면 상대 캐시가 사용됩니다. 파일 식별자가 변경되지 않은 경우 상대 캐시가 적용되고 클라이언트는 데이터를 가져오기 위해 계속해서 데이터를 캐시하므로 강제 캐시와 상대 캐시가 사용됩니다. 갈등이 아닙니다. 강제 캐싱과 상대 캐싱을 함께 사용하면 요청된 데이터를 적시에 업데이트하면서 서버에 대한 부담을 줄일 수 있습니다.

또 한 가지 주의할 점은 두 개의 상대 캐시 파일 식별자가 동시에 설정되면 둘 다 변경되지 않을 때까지 캐시가 적용되지 않는다는 것입니다.

sendFile(){
 if(this.handleCache(req,res,filepath,statObj)) return; //如果走缓存,则直接返回。
 res.setHeader('Content-type',mime.getType(filepath)+';charset=utf-8');
 let encoding = this.getEncoding(req,res); //获取浏览器能接收的编码并选择一种
 let rs = this.getStream(req,res,filepath,statObj); //支持断点续传
 if(encoding){
  rs.pipe(encoding).pipe(res);
 }else{
  rs.pipe(res);
 }
}
로그인 후 복사

getEncoding

요청 헤더에서 브라우저가 받아들일 수 있는 인코딩 유형을 가져오고, 정규 일치를 사용하여 첫 번째 것과 일치시키고, 해당 zlib 인스턴스를 생성하고 이를 sendFile 메소드에 반환합니다. 반환될 수 있습니다. 파일이 인코딩되었습니다.

handleCache(req,res,filepath,statObj){
 let ifModifiedSince = req.headers['if-modified-since']; //第一次请求是不会有的
 let isNoneMatch = req.headers['is-none-match'];
 res.setHeader('Cache-Control','private,max-age=30');
 res.setHeader('Expires',new Date(Date.now()+30*1000).toGMTString()); //此时间必须为GMT
 
 let etag = statObj.size;
 let lastModified = statObj.ctime.toGMTString(); //此时间格式可配置
 res.setHeader('Etag',etag);
 res.setHeader('Last-Modified',lastModified);
 
 if(isNoneMatch && isNoneMatch != etag) return false; //若是第一次请求已经返回false
 if(ifModifiedSince && ifModifiedSince != lastModified) return false;
 if(isNoneMatch || ifModifiedSince){
 // 说明设置了isNoneMatch或则isModifiedSince且文件没有改变
  res.writeHead(304);
  res.end();
  return true;
 }esle{
  return false;
 }
}
로그인 후 복사

getStream

분할된 전송은 주로 요청 헤더의 req.headers['range']를 사용하여 수신할 파일이 어디에서 시작되는지 확인합니다. ? 하지만 이 부분의 데이터는 실제로 fs.createReadStream을 통해 읽혀집니다.

getEncoding(req,res){
 let acceptEncoding = req.headers['accept-encoding'];
 if(/\bgzip\b/.test(acceptEncoding)){
  res.setHeader('Content-Encoding','gzip');
  return zlib.createGzip();
 }else if(/\bdeflate\b/.test(acceptEncoding)){
  res.setHeader('Content-Encoding','deflate');
  return zlib.createDeflate();
 }else{
  return null;
 }
}
로그인 후 복사

명령줄 도구에 패키징됨

명령줄에 npm start 를 입력하여 dev-server를 시작하는 것처럼 사용자 정의할 수 있습니다. > 정적 서버를 시작하는 시작 명령입니다.

구현의 일반적인 아이디어는 다음과 같습니다. 시작 명령과 packge.json의 bin 특성 아래에 이 명령을 실행하는 파일의 경로를 구성합니다. 그런 다음 배치 파일을 준비하고 정적 서버 파일을 파일에 삽입하고 서버를 실행한 다음 이 파일을 노드 링크해야 합니다.

위 내용은 모두를 위해 제가 정리한 내용입니다. 앞으로 모든 사람에게 도움이 되기를 바랍니다.

관련 기사:

vue2.0에서 스타일/css 로더를 설치하는 방법

Vue2.0 이벤트 방송 및 수신(관찰자 모드)

vue 프로젝트 국제화 vue-i18n 설치 사용법 튜토리얼

위 내용은 Node.js를 사용하여 정적 서버를 구현하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿
회사 소개 부인 성명 Sitemap
PHP 중국어 웹사이트:공공복지 온라인 PHP 교육,PHP 학습자의 빠른 성장을 도와주세요!