ウェブ地図でベクトルタイル(pbf)を読むときに何が起こっているのか？


## はじめに
自分で作ったウェブ地図を観察してみました。mapbox GL JSにしろ、MapLibreにしろ、ArcGIS Onlineにしろ、ウェブ地図からベクトルタイルを読むときには、タイルがおいてあるURLにGETリクエストを出しています。

mapboxとmaplibreでは挙動は同じようだと想像しますが、今回はmapbox gl jsのver. 1ライブラリをつかって、どんな感じなのか見てみました。


## 手順と結果

### Step 1：何をしりたいのかを整理する
ベクトルタイルのリクエストに対してユーザー認証をかけた場合、クロスオリジンでCredentialを利用しないといけないようなことも書いてあります。そのようなことを試してみたのですが、あまりうまくいかなかったので、そもそもリクエストのヘッダーにセッションの情報等がどのくらい入っているのか確認してみたいと思っていました。

ベクトルタイルサーバー側、ウェブ地図サーバー側それそれで、少し設定を変えたときにリクエストヘッダがどのように変わるのか観察したいと思いました。

#### 知りたいこと１：ウェブ地図側の設定の影響
MapboxやMapLibreで、リクエストパラメターをいじって、headers: {'my-custom-header': true} や
credentials: 'include'を追加したときに、pbfタイルへのリクエストがどう変わるのか、見てみたいと思いました。（credentialを使うと、リクエストのときにクロスオリジンでもCookieを送るようになると書いてあります。）
[MapBox の requestparameters](https://docs.mapbox.com/mapbox-gl-js/api/properties/#requestparameters)
[MapLibre の requestparameters](https://maplibre.org/maplibre-gl-js-docs/api/properties/#requestparameters)

#### 知りたいこと２：ベクトルタイルサーバー側の設定の影響
CORSの設定はもともとしていましたが、credentials: trueも含めた場合が必要になると思います。ただ、こっちはタイルを返すレスポンスに影響を与えると思うので、リクエストヘッダーなどには影響を与えないはずです。

#### 知りたいこと３：アクセス方法の影響
ウェブ地図を読み込んだ時にpbfがリクエストされる方法が、自分で直接URLを入れたときの方法とどう違うのかも理解しておきたいと思いました。

#### 整理
とりあえず、credentialを使う場合と使わない場合の二つのケースについてヘッダーがどんな感じなのか見ればいいのと、それぞれについてウェブ地図からタイルにアクセスした場合とURLを指定して直接アクセスした場合の2パターンを確認してみたようと思います。

##### ケース１：　タイルリクエストにcredentialを使わない場合。
* ウェブ地図ではmy custom headerなし。
* ベクトルタイルサーバー側ではただのCORSだけ。（credentialなし）
* ウェブ地図からのタイルアクセスと、URL直接指定のタイルアクセスを確認する。
 
##### ケース２：　タイル リクエストにcredentialを使った場合。
* ウェブ地図ではmy custom headerにする。
* ベクトルタイルサーバー側ではCORSにcredentialも含める。
* ウェブ地図からのタイルアクセスと、URL直接指定のタイルアクセスを確認する。



### Step 2: ウェブブラウザではタイル（PBF）リクエストのヘッダが見られない？
ベクトルタイル（pbf）のリクエストをチェックしようとしたら、どうもブラウザでは Request HeadersはProvisional headersしか表示されないようです。自分のWeb地図だけでなくて、地理院地図Vectorのページを見てもそうでした（下図）。なお、これらのページはMapbox GL JSをライブラリとして使っています。

テキストフォントのpbfファイルだとリクエストヘッダがみられて、Cookieやrefererなどが見られるんですが、ベクトルタイルだとリクエストヘッダーが特殊なのかもしれません。
![2021-12-22-header.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/53524da4-2404-c48f-693b-a215f6218138.png)

### Step 3:　サーバーの設定を調整
仕方がないので、ベクトルタイル側で見ることにしました。
自分のベクトルタイルサーバーで、ベクトルタイルを返すところの前にconsole.logを入れて、リクエストが持っているセッション情報、クッキー情報、ヘッダー情報を見てみることにします。

```javascript:ベクトルタイル関係の部分
router.get(`/:t/:z/:x/:y.pbf`, 
 async function(req, res) {
  const t = req.params.t
  const z = parseInt(req.params.z)
  const x = parseInt(req.params.x)
  const y = parseInt(req.params.y)
  console.log(req.session)
  console.log(req.cookies)
  console.log(req.rawHeaders)
  ...
  res.send(...)
}
)
```

### Step 4:　結果の観察
#### 観察１
CORSのcredentialの調整がうまくいっていないのか、Web地図から参照されるベクトルタイルへのリクエストはCORS設定に関わらず同じような結果になりました。リクエストについて、Sessionの内容、cookies、ヘッダーが出てきますが、cookieは空ですし、接続セッションのidなども出てきません。

![VT-Open.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/04fc847d-9746-294b-3f4c-06720192815b.png)
（↑ CORSのCredential設定なし（ケース1）、Web地図からのアクセス）

![VT-credential2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/81702fcd-38ca-0187-6a38-e58f7b2446d9.png)
（↑ CORSのCredential設定あり（ケース2）、Web地図からのアクセス）

本当は、後者でcookieに何か入っていることを期待していたのですが、参照元がlocalhostのhttpでやったので、ここら辺がダメなのかもしれません。

一方で、WebブラウザでURLを直接指定してタイルを読むと、セッションの中ではベクトルタイルサーバーで使ったUserIdが認識されていますし、cookieの中に、connect.sid があることがわかります。

![VT-credential-direct-id.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/a40344b4-7fdb-089d-c632-240685375de6.png)
（↑ ブラウザからURLを直接指定してのアクセス。ケース1、2ともに直前のセッション情報が引き継がれている様子）

#### 観察２
少し視点を変えて、セッションがどうなっているかを中心にみてみました。

同じドメイン（オリジン）のウェブ地図からタイルをみると、リクエストは一つのセッションのなかで扱われているのでセッション数は増えません。
![2021-01-04-fromSameDomain.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/c7da6ad2-84b3-87b4-299e-34975fb07621.png)

他のドメインのウェブ地図からのタイルリクエスト（異なるオリジン）では、タイルへのリクエストがそれぞれ独立したセッションとして扱われています。これでは認証に耐えられないと思います。（ArcGISオンラインなどはタイルリクエストのクエリでトークンをつけているのはこういう背景があるのかもしれません。）
![2021-01-04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/9aec0f42-6b67-43b8-86c3-a56d4c4be7f0.png)



### Step 5:　再チャレンジ
タイルのリクエストの際のcredentialの設定がどうも上手くできていないようなので、いろいろ見てみました。
[MapBox の requestparameters](https://docs.mapbox.com/mapbox-gl-js/api/properties/#requestparameters)
[MapLibre の requestparameters](https://maplibre.org/maplibre-gl-js-docs/api/properties/#requestparameters)

上のリンクでは、タイルリクエストのresourceTypeがSourceなんですが、ここが怪しいと思ってしらべてみると、どうやらタイルへのリクエストのresourceTypeはTileらしいです。（ドキュメントなしですが、 [ここ](https://github.com/mapbox/mapbox-gl-js/issues/6871) の記載が参考になりました。

resourceTypeをTileにしたところ、まだエラーがありますが、リクエストの所にpreflightがでてきました。resourceTypeはTileでもう少し実験を進めます。
![2021-01-04-CORS-Tile.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/c568c606-b7a5-043a-ba7d-80e8ab336524.png)


## まとめ
どうもウェブ地図からpbfを読み込むときのCookieの調整がうまく出来ていないのですが、当面の目標はpbfタイルリクエストにcookieをつけて、connect.sidを送れるように少しチャレンジしてみようかと思います。
ローカルでやったのをGitHubページなどでやってみて、httpsでのリクエストでどうなるかなど確認してみようと思います。

また、今回の試行からの教訓として、「ウェブ地図からPBFベクトルタイルのリクエストを見た場合、Webブラウザ（開発モード）ではProvisional headersしか表示されませんよ」、というのが一つあたらしい発見としてありました。

## 参考
[MapBox の requestparameters](https://docs.mapbox.com/mapbox-gl-js/api/properties/#requestparameters)
[MapLibre の requestparameters](https://maplibre.org/maplibre-gl-js-docs/api/properties/#requestparameters)