IP アドレス確認くんを作る!!  powered by Node.js on Azure App Service

こんにちは、アーキテクトのやまぱんです。
補足コメントや質問、<font color="red">いいね、拡散</font>、是非お願いします🥺！
間違ってたら<font color="red">優しく</font>教えてください！

node.js を触るのはこれが 5 回目ぐらいなんですけど、今回本来のメインの検証をするための下準備でハマってしまった。


## きっかけ
・検証のため IP アドレス確認くんを作りたくなった
・作ってみるとつまった
・**ローカルでは動くのに、Azure App Service にデプロイすると動かないっていう状態**にハマる、沼る
・他にも詰まってる人がいそうだった
　Stack over flow や Qiita でも同じようなエラーになってる人がいた
・今後も作ることありそうなのでメモしとこ


## 事前準備
node.js、Azure CLI ,Express Generator  などはインストール済の Windows 環境で実施

## 手順

+ 1.管理者権限のターミナルにて express のひな形を作る
```powershell:ターミナル
express ipshow(任意の名前で可)
```
+ 2.作成されたディレクトリに移動
```powershell:ターミナル
cd ipshow
```
+ 3.依存関係のインストール
```powershell:ターミナル
npm install
```
+ 4.routes/index.jsを以下のコードに書き換え　<キーポイント：IP アドレスの取得>
```javascript:routes/index.js
var express = require('express');
var router = express.Router();

/* GET home page. */
router.get('/', function (req, res, next) {
  // クライアントのIPアドレスを取得する
  // x-forwarded-for ヘッダーがある場合はそれを使用し
  //ない場合は req.connection.remoteAddress を使用してクライアントのIPアドレスを取得
  const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
  res.render('index', { title: `IPアドレス確認くん`, ip: ip});
});

module.exports = router;
```

+ 5.views/index.jadeを以下のコードに書き換え
```javascript:views/index.js
extends layout

block content
  h1= title
  H2 your IP address and port No. is  ""#{ip}""
```

+ 6.bin/www を必要に応じてポート番号を変更
```javascript:bin/www
var port = normalizePort(process.env.PORT || '8080');
```


+ 7.ローカルでデプロイ
```
npm run start
```

### ローカルでの実行イメージ
ローカル IP なのでこんな感じになる、想定通り！！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982508/473eb7b6-9f29-1fdd-4214-bcc106a24b73.png)

+ 8.Azure App Service にデプロイ

```bash:Azure CLI 例
az webapp up --sku F1(またはB1など) --name <例：yamapaniptest> --resource-group <例：RG-IPCheck> --subscription <Subscription ID>　--location japaneast --plan AppPlan
```


```bash:実際に打ったコマンド例(Azure CLI)
az webapp up --sku B1 --name demo-Webapp --resource-group demo-sukiyanen --subscription XXXXXXXXXXX-XXX-XXXX-XXXX-XXXXXXXXXX83 --location japaneast --plan yamapanAppService --launch-browser 
```

下記のような感じで URL が表示されます。(下記は別のアプリのデプロイ画面)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982508/d7c60ca2-9e6d-54bb-ce23-0cac2bb0d80c.png)


### Azure App Service での 実行イメージ
無事クライアント端末のグローバル IP が返ってきていることが分かります。✨✨
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982508/b90c4046-b621-8f62-6686-27d180ed70ed.png)




## うまくいかなかったことメモ
この画面飽きるほど見ました😢😢
```:( Application Error ```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982508/ce9e7035-21af-dafb-9bbd-20f40de8e766.png)

### ひたすらデプロイに失敗した
[**ストリームログ**](https://learn.microsoft.com/ja-jp/azure/app-service/quickstart-nodejs?tabs=linux&pivots=development-environment-vscode#stream-logs)では以下のような、Error Message が出ていた
```Error: Cannot find module 'express'``` やら ``` 'MODULE_NOT_FOUND'```、やら ```requireStack: [ '/home/site/wwwroot/server.js' ] ```やら。


```bash:ストリームログ
2024-02-26T14:16:18.990816296Z Error: Cannot find module 'express'
2024-02-26T14:16:18.990819496Z Require stack:
2024-02-26T14:16:18.990822696Z - /home/site/wwwroot/server.js
2024-02-26T14:16:18.990825896Z     at Function.Module._resolveFilename (node:internal/modules/cjs/loader:1028:15)
2024-02-26T14:16:18.990828996Z     at Function.Module._load (node:internal/modules/cjs/loader:873:27)
2024-02-26T14:16:18.990831996Z     at Module.require (node:internal/modules/cjs/loader:1100:19)
2024-02-26T14:16:18.990835397Z     at Module.patchedRequire [as require] (/usr/local/lib/node_modules/applicationinsights/node_modules/diagnostic-channel/dist/src/patchRequire.js:14:46)
2024-02-26T14:16:18.990838597Z     at require (node:internal/modules/cjs/helpers:119:18)
2024-02-26T14:16:18.990841797Z     at Object.<anonymous> (/home/site/wwwroot/server.js:3:17)
2024-02-26T14:16:18.990851097Z     at Module._compile (node:internal/modules/cjs/loader:1198:14)
2024-02-26T14:16:18.990854197Z     at Object.Module._extensions..js (node:internal/modules/cjs/loader:1252:10)
2024-02-26T14:16:18.990857197Z     at Module.load (node:internal/modules/cjs/loader:1076:32)
2024-02-26T14:16:18.990860097Z     at Function.Module._load (node:internal/modules/cjs/loader:911:12) {
2024-02-26T14:16:18.990863297Z   code: 'MODULE_NOT_FOUND',
2024-02-26T14:16:18.990866297Z   requireStack: [ '/home/site/wwwroot/server.js' ]
2024-02-26T14:16:18.990869297Z }
```

:::note
考察と疑問
恐らく、大きな違いは Express generetor を使ったのがよかったみたいで、Azure App Serviceへのデプロイでも正常に動くするようになった。
深追いはしてないけど、成功時と失敗時でディレクトリ構成が違うので、それが原因だと思う。
今度からExpressを使うときは Express generetor ( ```Express ディレクトリ名``` コマンド) を使おう❣✨

以下コマンドで Express Generator はインストール可能(node.js が入っている前提)
```
npm install express-generator -g
```

~なんでローカルでは動いてたのかが少し謎~
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982508/4a6aa6ae-25e2-9f01-06aa-0ee49a97fa67.png)
いつかじっくりちゃんと考えてみたい。
:::

###  HTTP モジュールを使用した方法 
これは Azure App Service の作りの関係 (内部にプロキシの役割をするものがある) でクライアントの IP が返ってこない、正しく取得できない。

```
const http = require('http');

// サーバーを作成し、リクエストを処理する
const server = http.createServer((req, res) => {
  // クライアントのIPアドレスを取得する
  const ipAddress = req.connection.remoteAddress;
  
  // IPアドレスをレスポンスとして返す
  res.writeHead(200, { 'Content-Type': 'text/plain' });
  res.end(`Your IP address is: "${ipAddress}"\n`);
});

// サーバーを指定のポートで待機させる
const port = 8080;
server.listen(port, () => {
  console.log(`Server running at http://localhost:${port}/`);
});
```
+ 実行結果
 下記のように予約された IP アドレスが表示される。
 表示したい本来のクライアントの IP アドレスではない。
 ```Your IP address is: "::ffff:169.254.129.1"```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2982508/db152571-7502-e2fc-185c-fefa7d0422be.png)




## 参考？
+ Error: Cannot find module 'express' when running on Azure

https://stackoverflow.com/questions/44576294/error-cannot-find-module-express-when-running-on-azure

## 参考
+ Node.jsでリクエストから接続元のIPアドレスを取得する方法

https://minory.org/node-get-client-ip.html

+ Express Generator で作成されたファイルを触って Express を理解したい1：生成, yarn start, express.static, path.join

https://qiita.com/mml/items/96e9ad8b95fd7d6d60c1


## 謝辞
親愛なる仲間に助けていただきました。
ありがとうございました。