(Node.js) spdyモジュールを理解する

# はじめに
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に取って代わられ、非推奨となっています。

# 使用データ
[こちらの記事](https://qiita.com/T-ubu/items/545d9f995ef7496a2ec4)のコードを参考にさせていただいています。
使用したレンタルサーバについては、[こちらの記事](https://qiita.com/k96mz/items/e33f493be15e9253e2ff)で書いています。
使用したコードは[こちらのGitHubページ](https://github.com/k96mz/20250130spdy)にあります。

:::note info
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（ソースマップ） と呼ばれるファイルで、デバッグしやすくするためのファイルです。

こうすることで、ナビゲーションコントロールやスケールバーなどが正常に表示されるようになります。

![スクリーンショット 2025-01-30 10.45.09.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3684675/5f66628c-36fc-ea62-f1be-a4e314c2737f.jpeg)

# レンタルサーバで地図を表示する
### httpsに関するエラー

![スクリーンショット 2025-01-30 12.32.34.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3684675/e44bf772-656a-a6bb-0a14-91713b35c848.jpeg)

(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 に適応させ、エラーを防ぐことができます。

以下のコードを利用すると、エラーが解消しました。

```javascript: apps4.js
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

https://www.npmjs.com/package/spdy

https://nodejs.org/api/http2.html

https://www.npmjs.com/package/http2-express-bridge