この記事では主に Node.js 静的サーバーの実装方法を紹介します。非常に優れており、参考になります。
URL を入力すると、この URL は上のリソース (ファイル) に対応する可能性があります。サーバー ) はディレクトリに対応する場合もあります。したがって、サーバーはこの URL を分析し、さまざまな状況に応じてさまざまな処理を実行します。 この URL がファイルに対応する場合、サーバーはファイルを返します。 この URL がフォルダーに対応する場合、サーバーはこのフォルダーに含まれるすべてのサブファイル/サブフォルダーのリストを返します。 上記は静的サーバーが主に行うことです。
しかし、実際の状況はそれほど単純ではありません。取得した URL が間違っているか、対応するファイルやフォルダーがまったく存在しないか、一部のファイルやフォルダーがシステムによって保護されている可能性があります。クライアントには知られたくない。 したがって、これらの特殊な状況に対しては、いくつかの異なるリターンとプロンプトを作成する必要があります。
さらに、実際にファイルを返却する前に、クライアントといくつかの交渉を行う必要があります。 ブラウザごとに異なる戻り処理を実行するには、クライアントが受け入れることができる言語の種類、エンコード方法などを知る必要があります。 クライアントがデータをより適切に受信できるように、返されたファイルに関する追加情報をクライアントに伝える必要があります。ファイルはキャッシュする必要がありますか?また、どのようにキャッシュする必要がありますか? ファイルは圧縮されていますが、どのように解凍すればよいのでしょうか? 待ってください...
この時点で、静的サーバーが主に行うことのほとんどすべてを予備的に理解しました。さあ、構成ファイル
サーバーを起動するには、サーバー起動時のポート番号を知る必要があります。静的サーバーの作業ディレクトリ
static-server/ | | - bin/ | | - start # 批处理文件 | | | - src/ | | - App.js # main文件 | | - Config.js # 默认配置 | | ·- package.json
フレームワーク全体
Attendanceイベント関数 これは、デフォルトではバインドされたオブジェクト(ここでは小さなサーバーです)を指しますが、これは変更されますコールバック関数でサーバー配下のメソッドを呼び出すために、ラージ オブジェクト サーバーにアクセスします。
let config = { host:'localhost' //提升用 ,port:8080 //服务器启动时候的默认端口号 ,path:path.resolve(__dirname,'..','test-dir') //静态服务器启动时默认的工作目录 }
リクエストリクエストの処理 URLのパス名を取得し、それをサーバーのローカル作業ルートディレクトリアドレスと連結し、filenameメソッドとstatメソッドを使用してファイル名を返します。それはファイルまたはフォルダーです
これはファイルフォルダーです。readdir メソッドを使用してフォルダーの下のリストを返し、リストをオブジェクトの配列にラップし、ハンドルバーを使用して配列データをテンプレートにコンパイルし、最後に戻りますクライアントへのテンプレートはファイルであり、req、res、statObj、ファイルパスは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); } }
処理時に注意することキャッシュとは、キャッシュが強制キャッシュと比較キャッシュに分かれており、強制キャッシュの優先順位が相対キャッシュよりも高いことです。 つまり、強制キャッシュが有効な場合、相対キャッシュは使用されず、サーバーはリクエストを開始しません。 ただし、強制キャッシュが失敗すると、ファイル識別子が変更されていない場合は相対キャッシュが使用され、クライアントは引き続きデータをキャッシュしてデータを取得するため、強制キャッシュと相対キャッシュが使用されます。衝突しないでください。 強制キャッシュと相対キャッシュを併用すると、要求されたデータをタイムリーに更新しながらサーバーへの負荷を軽減できます。
もう 1 つ注意すべき点は、2 つの相対キャッシュ ファイル識別子が同時に設定されている場合、両方のキャッシュ ファイル識別子が変更されない限り、キャッシュは有効になりません。
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);
}
}
ブラウザが受け入れることができるエンコードタイプをリクエストヘッダーから取得し、通常のマッチングを使用して最初のものと一致させ、対応する 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; } }
分割送信は主にリクエストヘッダーの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にstyle/cssローダーをインストールする方法
vueプロジェクトの国際化 vue-i18nのインストール 使い方チュートリアル
以上がNode.jsを使用して静的サーバーを実装する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。