はじめに
node.jsのコードの中でspdyモジュールを使用する機会があったので、どのようなモジュールであるのか簡単にまとめたいと思います。
spdyモジュールとは
Node.js環境でSPDYおよびHTTP/2サーバーを構築するためのパッケージです。Node.jsの標準的なHTTPモジュールのインターフェースを活用しつつ、SPDYやHTTP/2プロトコルをサポートするサーバーを作成できます。 
Expressフレームワークとも互換性があります。また、SPDYやHTTP/2をサポートしていないクライアントに対しては、通常のHTTPS通信にフォールバック(HTTP/1.1を使用)する機能も備えています。 
ただし、最新バージョン(4.0.2)は約5年前に公開されており、それ以降更新が行われていません。SPDY自体はHTTP/2に取って代わられ、非推奨となっています。
使用データ
こちらの記事のコードを参考にさせていただいています。
使用したレンタルサーバについては、こちらの記事で書いています。
使用したコードはこちらのGitHubページにあります。
htdocsフォルダの中に、「mapbox-gl_r.css」がありますが、これは「mapbox-gl.css」と比較して、著作権の背景を半透明から透明にしたものとおもわれます
ちなみにファイルサイズを比較したところ、どちらも34kbだったので、ほとんど同じファイルなのかもしれません。
npm install mapbox-gl@1.13.0
で必要なファイルをダウンロードします。
node_modules/mapbox-gl/dist/
にあるmapbox-gl.cssとmapbox-gl.jsをコピーして移動させます。
元からあった、mapbox-gl_r.cssとmapbox-gl.js.mapは削除しました。
ちなみに、mapbox-gl.js.map は Source Map(ソースマップ) と呼ばれるファイルで、デバッグしやすくするためのファイルです。
こうすることで、ナビゲーションコントロールやスケールバーなどが正常に表示されるようになります。
レンタルサーバで地図を表示する
httpsに関するエラー
(failed) net::ERR_HTTP2_PROTOCOL_ERROR というエラーが mapbox-gl.js の読み込み時に発生しています。
curl -I --http2 https://k96mz.net:3000/mapbox-gl.js
とすると、
HTTP/2 200
が返ってくるので、リクエスト自体は成功しているようです。
おそらくですが、SPDYモジュールがメンテナンスされていない影響でエラーが出ているのではないかと思われます。
apps4.jsファイルを作成し、spdyではなくHTTP/2モジュールを使用します。
HTTP/2モジュールは組み込みモジュールなので、追加インストールは必要ありません。
http2-express-bridgeもインストールします。
npm i http2-express-bridge
http2-express-bridge は、express を http2(HTTP/2)で動作させるためのラッパー です。
通常、express は http2.createSecureServer() に直接渡せません。
このモジュールを使うことで、express を HTTP/2 に適応させ、エラーを防ぐことができます。
以下のコードを利用すると、エラーが解消しました。
const config = require('config');
const fs = require('fs');
const express = require('express');
const http2 = require('http2');
const cors = require('cors');
const morgan = require('morgan');
const winston = require('winston');
const DailyRotateFile = require('winston-daily-rotate-file');
const http2Express = require('http2-express-bridge'); // 修正ポイント
// config constants
const morganFormat = config.get('morganFormat');
const htdocsPath = config.get('htdocsPath');
const privkeyPath = config.get('privkeyPath');
const fullchainPath = config.get('fullchainPath');
const port = config.get('port');
const mbtilesDir = config.get('mbtilesDir');
const logDirPath = config.get('logDirPath');
// SSL証明書の存在チェック
if (!fs.existsSync(privkeyPath) || !fs.existsSync(fullchainPath)) {
console.error('❌ SSL証明書ファイルが見つかりません!');
process.exit(1);
}
// logger configuration
const logger = winston.createLogger({
transports: [
new winston.transports.Console(),
new DailyRotateFile({
filename: `${logDirPath}/server-%DATE%.log`,
datePattern: 'YYYY-MM-DD',
}),
],
});
logger.stream = {
write: message => {
logger.info(message.trim());
},
};
// **修正: Express アプリを HTTP/2 対応にする**
const app = http2Express(express);
const VTRouter = require('./routes/VT'); // tiling
app.use(cors());
app.use(
morgan(morganFormat, {
stream: logger.stream,
})
);
app.use(express.static(htdocsPath));
app.use('/VT', VTRouter);
// **修正: Express を適切に HTTP/2 に適応**
const server = http2.createSecureServer(
{
key: fs.readFileSync(privkeyPath),
cert: fs.readFileSync(fullchainPath),
allowHTTP1: true, // HTTP/1.1 もサポート
},
app // Express を HTTP/2 対応版にしたものを渡す
);
// ポートが開けない場合のエラーハンドリング
server
.listen(port, () => {
console.log(`✅ HTTP/2 Server running on https://localhost:${port}`);
})
.on('error', err => {
if (err.code === 'EADDRINUSE') {
console.error(`⚠️ ポート ${port} はすでに使用されています!`);
} else {
console.error(`🚨 サーバー起動エラー:`, err);
}
});
上記コードで実行するとエラーは何も出ないので、今後はこちらのコードを使用すると良いかもしれません。
まとめ
node.jsのspdyモジュールの使用方法とそのエラー、及び対処方法について記載しました。
Reference