Webを支える技術②　~URI~

# はじめに

前回「Webを支える技術」の概要とRESTについてまとめた。

今回はWebを支える技術の下記3つのうちURIについてまとめる。

1. URI
2. HTTP
3. HTML

# URIの仕様

## URIとは

URIとはUniform Resource Identifierの略で、「リソースを統一的に識別するID」のこと。

つまり、「同じルールのもと制定された、リソースを一意に指し示すための名前/ ID」のこと。

なのでURIさえあれば全てのリソースに対して簡単にアクセスできる。

この特徴を実現するための秘密は、URIの構文にある。

## URIの構文

URIの構文は下記のようなもの。

```ｈｔｍｌ
http://blog.example.jp/entries/1
```

このURIを構成するパーツは次のように分解できる。

- URIスキーム: http
    
    →プロトコルを示すのが一般的。
    
- ホスト名: blog.example.jp
    
    →DNSで名前が解決できるドメイン名かIPアドレス。インターネット上で必ず一意になる。
    
- パス: /entries/1
    
    →そのホストの中でリソースを一意に指し示すパス。
    

このように、インターネット上で必ず一意になるホスト名と、ホスト内で必ず一位になるパスを組み合わせることで、URIは世界中の他のリソースと重複しないようになっている。

### URIに持たせられるその他の情報

実はURIにはもっと複雑な情報を持たせることもできる。

```ｈｔｍｌ
http://hinako:pass@blog.example.jp:8000/search?q=test&debug=true#n10
```

先ほどの例にはなかったものは次の通り。

- ユーザー情報: hinako:pass
    
    →リソースにアクセスする際のユーザー情報で、ユーザー名とパスワードを「:」で区切る。
    
- ポート番号: 8000
    
    →このホストにアクセスするときのプロトコルで用いるTCPのポート番号。省略するとHTTPのデフォルトの80になる。
    
- クエリパラメータ: q=test&debug=true
    
    →検索キーワードなど、クライアントから動的にURIを生成するときに利用する。
    
- URIフラグメント: #n10
    
    →URIが指し示すリソース内部の特定の部分を示すときに利用する。HTML文書であれば、id属性の値を読み取る。
    

## 絶対URIと相対URI

URIのパスはUNIXのファイルシステムと同じような階層構造を持っており、またファイルシステムと同じように絶対パスと相対パスで示すことができる。

相対URIの場合、通常はそのリソースのURIが起点になるが、<base>タグを用いると起点とするベースURIを明示的指定することもできる。

```jsx
<head>
  <title>test</title>
  <base href="https://test.jp/" />
</head>
```

相対URIでは、相対パスと同様に「.」や「..」を使える他、「/」から始まる相対URIはホスト名からのパスとして解釈される。

## URIで使用できる文字

URIの使用では、次の文字がURIのパスに使えると定められている。

・アルファベット：A-Za-z

・数字：0-9

・記号：.~:@!$&'()

上記以外の文字列、日本語などをURIに入れる場合は%エンコーディングでその文字をエンコードする。

%エンコーディングでは文字を構成するバイトそれぞれを「%xx」（xxは16進数）で表現する。

注意点として、たとえば同じ「あ」でも文字コードが違えばエンコード結果は異なる。

サーバが提供するURIであればサーバが%エンコードしているので問題ないが、クライアント側でフォームを使って動的にURIを生成する場合は、そのフォームを提供しているWebページとの文字エンコーディングと合わせておく必要がある。

## URIの実装で気をつけること

相対URIの解決と%エンコーディングの扱いには気を付ける必要がある。

クライアントで相対URIを解決するには面倒な処理が必要になるので、WebサービスやWebAPIを実装する場合にはなるべく絶対URIを使った方がクライアントにとって親切。

%エンコーディングの文字エンコーディングとしては、混乱をさけるためになるべくUTF-8を用いるのが望ましい。

本書では上記の通り述べられており、実際今から新しく構築するならばUTF-8を使うのが良いと思うが、Shift-JISが使われている既存のWebサービスを拡張したり、そのサービスと組み合わせてサービスを構築するような場合の文字コードの扱いは難しいなと感じる。

# URIの設計

## 良いURIは変わらない

Webはそれぞれのリソースに他のリソースへのリンクが埋め込まれたハイパーメディアシステムなので、URIが変わりリンクが切れてしまうことは、ハイパーメディアシステムが機能しないことを意味する。

そのためURIは変わらないべきである。

変わりにくいURIを設計するための指針を挙げていく。

### プログラミング言語に依存した拡張子やパスを含めない

ある特定の実装言語に依存した文字列をURIに含めると、その言語を変更した途端にそのURIは使えなくなってしまう。

プログラムの実装時に言語に依存した表記をURIに含めないこともだが、Webサーバーの.htaccessファイルの設定でファイルの拡張子を非表示にすることも工夫のひとつかなと思った。

[.phpや.htmlなどの拡張子をURL表示させない方法 - ウェブのこと](https://emily-web.hatenablog.com/entry/2019/04/30/.php%E3%82%84.html%E3%81%AA%E3%81%A9%E3%81%AE%E6%8B%A1%E5%BC%B5%E5%AD%90%E3%82%92URL%E8%A1%A8%E7%A4%BA%E3%81%95%E3%81%9B%E3%81%AA%E3%81%84%E6%96%B9%E6%B3%95)

### メソッド名やセッションIDを含めない

メソッド名はリファクタリングをすると変わる可能性があるし、セッションIDはログインのたびに変わるので、これらをURIに含めない。

### URIはリソースを表現する名詞にする

URIはリソースの名前なので、名詞であるべき。

初期のRuby on Railsでは、下記のようなURIが一般的だったらしい。

```ｈｔｍｌ
http://example.jp/sample/show/123
```

「show」という動作がURIで示されているが、リソースを取得するのか更新するのかといった動作については、URIではなくHTTPメソッドで決定するのがHTTPの作法。

URIとHTTPメソッドは、名刺と動詞の関係にあるべき。

## URIを変更する場合にはリダイレクトするように

どうしてもURIを変更したいときは、出来る限りリダイレクト（古いURIから新しいURIに転送）するようにすると良い。

リダイレクトされている古いURIをクライアントが取得すると、次のようなレスポンスが帰り、Locationヘッダで明示された新しいURIを自動的に取得しにいく。

```
HTTP/1.1 301 MovedPermanently
Location:http://example.jp/new
```

リダイレクトを実現するしくみはHTTPサーバが用意している。

調べてみると、Apacheであれば.htaccessにmod_rewriteモジュールの設定を記述、nginxであればnginx.confにrewriteの設定を記述することでリダイレクトを行うことができるらしい。

## URIの不透明性

URIは可読性が高いため、ユーザーがURIの構造を推測しやすくなる。

しかしクライアント側はあくまでサーバが提供するURをそのまま扱うだけであるべきで、URIの内部構造を推測して操作したりクライアント側でURIを構築したりすべきではない。

なぜなら推測してもそこにリソースがあるとは限らないし、サーバ側の実装でURIの構造を変更した場合に、システムが動かなくなるという密結合状態になってしまうため。

URIをクライアント側で組み立てたり、拡張子からリソースの内容を推測したりできないことを、「URIはクライアントにとって不透明である」と言い、クライアントを作る際はURIが不透明であることを心がけないといけない。

# さいごに

「インターネット上で必ず一意になるホスト名と、ホスト内で必ず一位になるパスを組み合わせることで、URIは世界中の他のリソースと重複しないようになっている」という点は、言われてみれば当たり前なのだが、よくできた仕組みだなぁと思った。

「Webはそれぞれのリソースに他のリソースへのリンクが埋め込まれたハイパーメディアシステムなので、URIが変わりリンクが切れてしまうことは、ハイパーメディアシステムが機能しないことを意味する」というのもよく考えれば当たり前のことだが、非常に納得感があった。

変わらないURIのための設計を心がけていきたい。

先日読んだ「プリンシプルオブプログラミング」という本に、「コードは設計書である」という言葉があったが、URI設計においても、リソースの表現が上手くできていればURI自体が設計書代わりにもなると思った。