クライアントから送信されたHTTPリクエスト情報を表示するWebページを提供する

Aug 21 2020

NodeとJavaScriptでWebサーバーのプログラミングを学ぶために、私は1つのことだけを行う単純なWebサーバーを実装することにしました。

  • HTTPリクエストのデータをHTMLテーブルとして表示します。

表示する実際のデータは任意です。この例では、ヘッダーの内容を、メソッド、URL、およびhttpバージョンとともに表示しています。

実用的な解決策は次のとおりです。

const http = require('http');

const port = 3344;

const htmlCSS = `
  <style>
    body {
      font-family: sans-serif;
    }

    td {
      border: 1px solid black;
      padding: 0.5rem;
    }

    table {
      margin: 0 auto;
    }
  </style>
`;

const server = http.createServer((req, res) => {
  const {
    headers,
    method,
    url
  } = req;

  console.log(`\n${headers['user-agent']}\n${method}\n${url}`); console.log(new Date()); console.log(); writeResponse(req, res); }); server.listen(port); function writeResponse(req, res) { res.statusCode = 200; res.setHeader('Content-Type', 'text/html'); writeBody(req, res); res.end(); } function writeBody(req, res) { const htmlTitle = '<title>Your Request Is</title>'; const htmlEncode = '<meta charset="UTF-8">'; const htmlHead = `<head>${htmlTitle}${htmlCSS}${htmlEncode}</head>`;
  const htmlTop = `<html lang="en">${htmlHead}<body>`; const htmlBot = '</body></html>'; res.write(htmlTop); writeTable(req, res); res.write(htmlBot); } function writeTable(req, res) { const htmlTableTop = '<table><tbody>'; const htmlTableBot = '</tbody></table>'; res.write(htmlTableTop); writeAllRows(req, res); res.write(htmlTableBot); } function writeAllRows(req, res) { const { httpVersion, httpVersionMinor, httpVersionMajor, headers, method, url } = req; for (const key in headers) { writeRow(res, key, headers[key]); } writeRow(res, 'method', method); writeRow(res, 'url', url); writeRow(res, 'httpVersion', httpVersion); writeRow(res, 'httpVersionMinor', httpVersionMinor); writeRow(res, 'httpVersionMajor', httpVersionMajor); } function writeRow(res, key, val) { const entry = `<tr><td>${key}</td><td>${val}</td></tr>`;
  res.write(entry);
}

特定の質問がありますが、あらゆる種類のフィードバックを楽しみにしています!ですから、改善できることがあれば、コメントをいただければ幸いです。

  • この作業を簡単にするために他のモジュールを使用できますか?
  • これほど単純な仕事の場合、HTMLとCSSを別々のファイルとして扱う価値はありますか?
  • HTMLとCSSは通常JSファイル内でどのように処理されますか(編集、追加など)?
  • HTMLとCSSの構築をどの程度うまく処理していますか?
  • これはもっと簡潔に行うことができますか?
  • 何らかの方法でこれを改善するために、あなたは何を変えますか?

回答

5 ManuelSpigolon Aug 21 2020 at 20:07

この作業を簡単にするために他のモジュールを使用できますか?

fastifyやexpressなどのWebフレームワークを使用できます。これにより、コードが大幅に簡素化されます

これほど単純な仕事の場合、HTMLとCSSを別々のファイルとして扱う価値はありますか?

プロジェクトが成長すると仮定すると、「静的テキスト」を別のファイルに移動することをお勧めします。

HTMLとCSSは通常JSファイル内でどのように処理されますか(編集、追加など)?

サーバーサイドレンダリング(SSR)を手作業で作成しました。あなたのようにいくつかのfremeworkを使用することができ、手動で文字列のすべてのそれらの作品を管理するのは難しいだろうし、また、いくつかのスクリプトインジェクションにdandgerousなりますのでVUEなど他のテンプレートシステムhandlebarsjs等-ここにリスト

HTMLとCSSの構築をどの程度うまく処理していますか?

これらの値の処理を開始すると、そのようなリンクにセキュリティ上の問題が発生する可能性があります。

http://localhost:3000/?user=%3Cimg%20src=%27aaa%27%20onerror=alert(1)%3E

フレームワークは通常、これらのケースからユーザーを保護します。

このコード:

  const htmlTitle = '<title>Your Request Is</title>'
  const htmlEncode = '<meta charset="UTF-8">'
  const htmlHead = `<head>${htmlTitle}${htmlCSS}${htmlEncode}</head>` const htmlTop = `<html lang="en">${htmlHead}<body>`

毎回同じ出力文字列を生成するため、すべてのリクエストの代わりに1回実行できます。これにより、高スループットサイトのnodejsガベージコレクターのストレスが軽減されます。

これはもっと簡潔に行うことができますか?

いくつかの関数を使用してObject、より少ないコードを書くことができArrayます。

function stringTemplates (request) {
  return `<html lang="en">
<head>
<title>Your Request Is</title>
</head>
<body>
<table><tbody>
${Object.entries(request.headers).map(processLine).join('')} ${['httpVersion', 'httpVersionMinor', 'httpVersionMajor', 'method', 'url'].map(prop => processLine([prop, request[prop]])).join('')}
</tbody></table>
</body>
</html>
`
}

function processLine ([header, value]) {
  return `<tr><td>${header}</td><td>${value}</td></tr>`
}

何らかの方法でこれを改善するために、あなたは何を変えますか?

これはGETのみを示していますが、HTTP標準を学習するには、次のように表示すると便利です。

  • クエリパラメータ
  • フォームパラメータ(異なるエンコーディング)
2 SᴀᴍOnᴇᴌᴀ Aug 21 2020 at 22:27

何らかの方法でこれを改善するために、あなたは何を変えますか?

どれくらいの費用がかかるかはわかりませんres.write()が、電話の回数を最小限に抑えることを目指しています。このために、行を生成して文字列を返し、各行の文字列を配列に収集し、を使用Array.prototype.join()して配列を結合し、への単一の呼び出しに渡す関数がありますres.write()


このコードはconst、変数のスコープを制限し、偶発的な再割り当てを回避するためにうまく利用されています。また、実行時に変更されてはならない定数値にも使用できます。

定数は大文字または小文字で宣言できますが、一般的な規則では、すべて大文字を使用します。1

のような名前htmlCSSHTML_CSS、であるport可能性がありますPORT。そうすれば、コードを読んでいる人なら誰でも、これらの値を変更してはならないことがわかります。で宣言されたオブジェクト/配列はconst、への呼び出しでラップされない限り不変ではないことに注意してくださいObject.freeze()。