Heim  >  Artikel  >  Web-Frontend  >  So implementieren Sie einen statischen Server mit Node.js

So implementieren Sie einen statischen Server mit Node.js

亚连
亚连Original
2018-06-02 14:55:241356Durchsuche

In diesem Artikel wird hauptsächlich die Implementierungsmethode des statischen Node.j-Servers vorgestellt. Sie ist sehr gut und hat Referenzwert.

Wenn Sie eine URL eingeben, kann diese URL entsprechen Eine Ressource (Datei) auf dem Server kann auch einem Verzeichnis entsprechen. Daher analysiert der Server diese URL und führt für verschiedene Situationen unterschiedliche Aktionen aus. Wenn diese URL einer Datei entspricht, gibt der Server die Datei zurück. Wenn diese URL einem Ordner entspricht, gibt der Server eine Liste aller in diesem Ordner enthaltenen Unterdateien/Unterordner zurück. Das Obige ist, was ein statischer Server hauptsächlich tut.

Aber die tatsächliche Situation ist nicht so einfach. Die URL, die wir erhalten, ist möglicherweise falsch und die entsprechende Datei oder der entsprechende Ordner existiert möglicherweise überhaupt nicht, oder einige Dateien und Ordner existieren möglicherweise überhaupt nicht. Was vom System geschützt wird, ist verborgen, und wir möchten nicht, dass der Kunde davon erfährt. Daher müssen wir für diese besonderen Situationen einige unterschiedliche Rückgaben und Eingabeaufforderungen vornehmen.

Bevor wir eine Datei tatsächlich zurücksenden, müssen wir außerdem einige Verhandlungen mit dem Kunden führen. Wir müssen die Sprachtypen, Codierungsmethoden usw. kennen, die der Client akzeptieren kann, um unterschiedliche Rückgabeverarbeitungen für verschiedene Browser durchzuführen. Wir müssen dem Client einige zusätzliche Informationen über die zurückgegebene Datei mitteilen, damit der Client die Daten besser empfangen kann: Muss die Datei zwischengespeichert werden und wie sollte sie zwischengespeichert werden? Ist die Datei komprimiert? Wie soll sie dekomprimiert werden? Warten Sie...

An diesem Punkt haben wir ein vorläufiges Verständnis für fast alles, was ein statischer Server hauptsächlich tut, los geht's!

Implementierung

Projektverzeichnis

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

Konfigurationsdatei

Um einen Server zu starten, müssen wir die Portnummer beim Starten des Servers und das Arbeitsverzeichnis des statischen Servers kennen

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

Gesamtrahmen

Hinweis

Dies ist in der Ereignisfunktion standardmäßig das gebundene Objekt (hier ist der kleine Server), das heißt Hier geändert Server ist ein großes Objekt, um in der Callback-Funktion Methoden unter Server aufzurufen.

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;

Anfrageanfrageverarbeitung

Den Pfadnamen der URL abrufen und lokal arbeiten Auf dem Server wird die Stammverzeichnisadresse zusammengefügt und ein Dateiname zurückgegeben. Verwenden Sie die Methode „filename“ und „stat“, um zu erkennen, ob es sich um eine Datei oder einen Ordner handelt Ordner und wickeln Sie die Liste in ein Array von Objekten ein. Kombinieren Sie dann den Handler, um die Array-Daten in die Vorlage zu kompilieren, und geben Sie diese Vorlage schließlich an den Client zurück.

ist eine Datei, übergeben Sie req, res, statObj und Dateipfad zu sendFile und übergeben Sie ihn dann zur Verarbeitung an 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);
 }
}

[tip] Wir werden die Anforderungsmethode asynchron machen, damit wir asynchron schreiben können

Methode

sendFile

Beinhaltet Funktionen wie Caching, Codierung und segmentierte Übertragung

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);
 }
}

handleCache

Bei der Verarbeitung des Caches ist zu beachten, dass der Cache in erzwungenen Cache und Vergleichscache unterteilt ist Die Priorität des erzwungenen Caches ist höher als die des relativen Caches. Mit anderen Worten: Wenn der erzwungene Cache aktiv ist, wird der relative Cache nicht verwendet und der Server initiiert keine Anfrage. Sobald der erzwungene Cache jedoch fehlschlägt, wird der relative Cache verwendet. Wenn sich die Dateikennung nicht geändert hat, wird der relative Cache wirksam und der Client speichert die Daten weiterhin zwischen, sodass der erzwungene Cache und der relative Cache verwendet werden nicht in Konflikt geraten. Wenn erzwungenes Caching und relatives Caching zusammen verwendet werden, kann dies die Belastung des Servers verringern und gleichzeitig dafür sorgen, dass die angeforderten Daten zeitnah aktualisiert werden.

Außerdem ist zu beachten, dass der Cache nur dann wirksam wird, wenn sich keine der beiden relativen Cache-Dateikennungen geändert hat, wenn zwei relative Cache-Dateikennungen gleichzeitig festgelegt werden.

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;
 }
}

getEncoding

Rufen Sie den Codierungstyp ab, den der Browser aus dem Anforderungsheader akzeptieren kann, und verwenden Sie reguläres Matching Match Erstellen Sie im ersten Schritt die entsprechende zlib-Instanz und geben Sie sie an die sendFile-Methode zurück, damit sie bei der Rückgabe der Datei codiert werden kann.

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;
 }
}

getStream

segmentierte Übertragung, hauptsächlich unter Verwendung von

im Anforderungsheader, um die Anforderung zu bestätigen Die empfangene Datei beginnt und endet jedoch tatsächlich.

req.headers['range']fs.createReadStream

getStream(req,res,filepath,statObj){
 let start = 0;
 let end = startObj.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])?0:parseInt(result[1]);
   end = isNaN(result[2])?end:parseInt(result[2])-1; //因为readstream的索引是包前又包后故要减去1
  }
 }
 return fs.createReadStream(filepath,{
  start,end
 });
}

ist in ein Befehlszeilentool gepackt

Wir können es wie folgt eingeben die Befehlszeile Starten Sie einen

und passen Sie einen Startbefehl an, um unseren statischen Server zu starten.

Die allgemeine Idee der Implementierung ist: Konfigurieren Sie einen Startbefehl und den Pfad der Datei, die diesen Befehl ausführt, unter dem bin-Attribut in packge.json. Dann müssen wir eine Batchdatei vorbereiten, unsere statische Serverdatei in die Datei einfügen, unseren Server laufen lassen und diese Datei dann mit einem Knoten verknüpfen.

Ich habe das Obige für Sie zusammengestellt und hoffe, dass es Ihnen in Zukunft hilfreich sein wird.

Verwandte Artikel:

So installieren Sie den Style-/CSS-Loader in Vue2.0

Vue2.0-Event-Broadcasting und Empfangen (Beobachtermodus)

Tutorial zur Installation und Verwendung des Vue-Projekts Internationalisierung vue-i18n

Das obige ist der detaillierte Inhalt vonSo implementieren Sie einen statischen Server mit Node.js. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn