2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

WEBを支える技術の要約

Posted at

https://www.amazon.co.jp/Webを支える技術-HTTP、URI、HTML、そしてREST-WEB-PRESS-plus/dp/4774142042
この本の要約を自分用に書きました。おかしな点等があれば、コメントお願いいたします。

WEBとは何か

ブラウザを通じてインターネットの向こう側にあるwebサーバーとやりとりしながら、私たちはyoutubeとかを見る。 webの用途は3つに分かれる。 ①webサイト ②ユーザーインタフェースとしてのWEB:テレビ、プリンタとかの設定をパソコン使ってやった方が便利なことがある。またHTMLによるヘルプの記述もそう。windowsにはhtmlヘルプ(意味のわかりにくい単語にハイパーリンクが設定されており、クリックすると解説が書かれたページにジャンプする。)という機構があり、HTMLをベースにソフトウェアやハードウェアのヘルプを作成できる。 ③プログラム用APIとしてのWEB:ユーザーインタフェースだけでなく、APIというプログラム用のインターフェースとしても利用されている。

WEBを支える技術

HTTP,URI,HTMLがWEBを支える基本的な技術。URIを使えば世界中のあらゆる情報を指し示せる。HTMLはそれらの情報を表現する文書フォーマット。そしてHTTPというプロトコル(コンピューター同士の通信をする際の手順や規格のこと)を使ってそれらの情報を取得したり発注したりする。 この3つの技術によって支えられたWEBは情報システムとして見ると、ハイパーメディアシステムと、分散システムの二つの側面を持っている

ハイパーメディア

ハイパーメディアとはテキストや画像、音声など様々なメディアをハイパーリンクで結びつけて構成したシステム。はいぱメディア以前(書籍や映画は線形的に先頭から順に読む)のに対し、ハイパーメディアは非線形的にユーザが自分でリンクを選択して情報を取得する。 ハイパーリンクorリンクとはハイパーメディアにおいて情報同士を結びつける機構のこと。htmlで記述されたWEbページには他のWEBページや埋め込まれた画像へのリンクが含まれる。

分散システム

一つの中央コンピュータが全てを処理する形式を集中システムという。これに対して複数のコンピュータを組み合わせて処理を分散させる形式を分散システムと呼ぶ。WEBは世界中に配置されたサーバに世界中のブラウザ(WEBサイトを閲覧するために使うソフトのこと)がアクセスする分散システム。

WEBの歴史

WEBが持つ歴史的背景をハイパーメディアシステムと分散システムの二つの側面から解説していきます。

WEb以前のインターネット

初期のインターネットにはWEBがなかった。 インターネットの起源は1969年に構築されたARPANETまで遡る。これは研究機関を繋ぐためのネットワーク。 WEB以前のインターネット環境は、リアルタイムに相手とやり取りするTCP/IPではなく、バケツリレー方式のUUCPによる転送も存在したので、情報の到達までに遅延があった。

WEB以前のハイパーメディア

ハイパーメディアの起源はARPANETの誕生からさらに遡った1945年のMemexという情報検索システムに関する論文に影響を受けたネルソンが生み出した。ネルソンはハイパーメディアとハイパーテキストという言葉を考案した。ハイパーテキストは文字情報中心の文章を相互にリンクさせた概念であるのに対し、ハイパーメディアはその考えを拡張し、音声や画像なども相互にリンクさせた概念。 その後のWEB以前に成功を収めたハイパーメディアとしては、Hyper Cardがある。これにはネットワークを通じてリンクをやり取りする機能はないものの、「カード」と呼ばれる文章を単位に相互にリンクを貼り、スクリプト言語によるプログラムを実行することができた。

Web以前のハイパーメディアの問題点

これまでに最も普及したハイパーメディアの実装はWEB。しかし旧来のハイパーメディア推進者の目からするとWEBは不完全なハイパーメディアのように映る。その理由はWebが単方向リンクしかサポートしていない。リンクが切れる可能性がある。バージョン管理やトランスクルージョン(ある文章中に他の文章断片への参照を埋め込みあたかも一つの文章のように見せる技術。)の機能がないなどがあげられる。しかし必要最低限のリンク機能だけを備えたいたのがWEBの成功要因である。旧来のハイパーメディアは複雑すぎた。

WEB以前の分散システム

昔は集中システムが主流だった。コンピュータが小型で高性能になると複数のコンピュータを組み合わせて処理を分散させ、全体としての性能を向上させる手法が登場する。

RPC

分散システムを実現するためには各サーバが提供する機能を他のサーバやクライアントから呼び出せる必要がある。RPCを用いるとリモートのサーバで実行しているプログラムをクライアント側から呼び出せる。 各社とも自社の分散システム技術を標準にしようと躍起になっていた。 RPCは関数を呼び出す仕組み。ただ現代的なプログラミング言語はほとんど全てがオブジェクト指向機能を備えている。そこで単なる関数呼び出しではなく、オブジェクト自体をリモート側に設置する分散オブジェクトと呼ばれる技術が考案された。ただ汎用的なオブジェクト機能を実装しようとしたため、仕様が非常に複雑になったのと、各社がバラバラで開発したため、互換性がないという問題があった。

Web以前の分散システムの問題点

RPCシステムに共通で存在する問題は ①性能劣化の問題:ネットワーク越しの関数呼び出しは、同一プロセス内で関数を呼び出すのに比べると何倍もの時間がかかる。一般に関数の粒度が小さいので目的を達成するために何回も関数を呼び出さないとならず、時間がかかる。 ②データ型変換の問題:プログラミング言語ごとにサポートするデータ型が異なるため、複数の言語が混在する環境ではデータ型の変換で問題が起きる。 ③インターフェースバージョンアップ時の互換性の問題:機能追加に伴ってサーバーのインターフェースを更新した場合、古いクライアントに対して下位互換性を保てない。 ④負荷分散の問題:一般にRPCベースのシステムはサーバ上にアプリケーション状態を保存する。そのためサーバ間でアプリケーション状態を共有しなければならず、多数のサーバーで負荷を分散することが難しい。 このようにWEB以前の分散システムは数を限定した均一なクライアントが前提だった。これでは世界規模で動作するシステムにはならない。

Webの誕生

1990年に最初のWebが生まれる。Webの普及を一気に推し進めたのがMosaicというブラウザ。これによって文字情報だけでなく、画像も扱えるようになった。

ハイパーメディアとしてのWeb

Webはインターネットを利用したハイパーメディアとして設計された。Web以前のハイパーメディアとの1番の違いはここ。インターネットを利用しているので不特定多数の情報をリンクさせあうことができる。その反面情報の集中的な管理は難しくなり、リンク切れが起きやすい。 Webが実現しているリンクはシンプルな単方向のリンクだけであることも特徴。元々のリンクの概念では外部からリンクを指定するといった拡張リンクの考え方も存在した。

分散システムとしてのWeb

RPCは閉じたネットワーク環境で、あらかじめ想定した数と種類のクライアントを相手にサービスを提供するシステムとしては優れている。Webはクラインアントとサーバ間のインターフェースをHTTPというシンプルなプロトコルで固定したことで不特定多数を相手できるようになった。

Webの標準化

Webを構成するHTTP,URI,HTMLの標準化が求められた。Web以前のインターネット標準は全てIETFのRFCとして定められてきたが、Webが急速に普及したため、仕様策定が追いつかず、各社がバラバラの仕様で実装を行ってしまった。 この問題を解決するため、各社が集まってW3Cをという団体を創設。HTMLとCSSの仕様がバラバラだったのを長い年月をかけて解消していったが、現在も問題は残っている(cf 「ブラウザ対応」という言葉)

RESTの誕生

Webアーキテクチャの決定に関わる重要な人物がロイフィールディング。彼はRESTというアーキテクチャスタイルを名付けた。

さまざまなハイパーメディアフォーマットの誕生

初期のWebではHTMLが唯一のハイパーメディアフォーマット。しかしWebの普及に伴ってHTMLでは対応できない様々な要望が生まれ、microformats,Atomとかが誕生した。 HtmlやAtomはXMLをベースにした構造化文書のためのマークアップ言語のため、データを記述するためには表記が冗長すぎる。そこで単純化のためにjsonが生まれた。

WebAPIをめぐる議論

初期のWEBは人が文書を読むためのシステム。しかしWEBの用途が多様化するとプログラムから自動処理を行いたいという要求が出る。

SOAPとWS-*

WEB上でも分散オブジェクトを実現しようとする動きが出た。その中でHTTPをアプリケーションプロトコルではなく、トランスポートプロトコルとして扱い、HTTPの上で独自のメッセージを転送するSOAPというプロトコルが生まれた。しかしこのSOAPに関連した周辺仕様(WS)がまた乱立してしまい、標準化戦争が起きた。

SOAP対REST

SOAPとRESTのどちらがアーキテクチャとして優れているから議論。アマゾンがSORPとREST形式でそれぞれWEB APIを提供したところRESTの方が圧倒的に多く使われた。RESTを否定する人はAmazonのようにセキュリティが必要ない簡単なWEBAPIではURIをGETするだけのシンプルなRESTの方が良い。しかし基幹システムなどでトランザクションや信頼性が必要なときはRESTでは不十分だと主張。

SOAPとWS-*の敗因

敗因は2つ。 SOAPはRPC/分散オブジェクトが持っていた技術的な問題点をそのまま継承してしまったという技術的な理由。 またSOAPの中でも標準化戦争の中で解釈に違いが生じ、相互運用性にかけてしまったという政治的な理由。

REST WEBのアーキテクチャスタイル

RESTはWebのアーキテクチャスタイル。MVC(model-view-controller)もアーキテクチャスタイルの一種。RESTは特にネットワークシステムのアーキテクチャスタイル。 WebのアーキテクチャスタイルはRESTでもあり、クライアント/システムでもある。クライアント/サーバアーキテクチャスタイルにいくつか制約を加えるとRESTというアーキテクチャスタイルになる。 実装→アーキテクチャ→アーキテクチャスタイルの順に抽象度が上がっていく(p27)

リソース

RESTにおける重要な概念の一つにリソースがある。リソースとはWEB上に存在する名前を持ったあらゆるもの(東京の天気予報、ブックマークetc)。リソースの名前がURIである。URIがなかった昔はいちいちファイルの取得方法を自然言語で書く必要があった。(p29) 一つのリソースが複数のURIを持つことが可能(ex todyと10/01 p29)。 サーバとクライアントでやりとりするデータのことをリソースの表現という。一つのリソースは複数の表現をもてる(html、pdfなど)

スタイルを組み合わせてレストを構成する

RESTは複数のアーキテクチャスタイルを組み合わせて構築した複合アーキテクチャスタイル。 クライアント/サーバに他のアーキテクチャスタイルを追加して制約を課していくことでRESTを構成する。

クライアント/サーバ

クライアント・サーバの利点は単一のコンピュター上で全てを処理するのではなく、クライアントとサーバに分離して処理ができること。これによりクライアントをPCだけでなくゲーム機とかにもできる。 またユーザーインターフェースはクライアントが担当するため、サーバはデータストレージの機能だけを提供すればよく、複数のサーバを組み合わせ(冗長化)ることで、可用性(故障が起きても復帰が早い)をあげられる。

ステートレスサーバ

クライアント・サーバに最初に追加するアーキテクチャスタイルがステートレスサーバ。ステートレスとは、クライアントのアプリケーション状態をサーバで管理しないこと。これだと、サーバ側の実装を簡単にできるというメリットがある。 現実にはステートフルなwebサービスがある(Cookieを使ったセッション管理など)。ステートレスだと、クライアントはリクエストごとに全ての情報を送る必要があるが、これだとログイン状態を保持してページを遷移することができないから、Coikieが使われる。 Cookieはステートレスサーバの利点を捨てることになることを理解した上で使用すること。

キャッシュ

次のアーキテクチャスタイルはキャッシュ。キャッシュとはリソースの鮮度に基づいて、一度取得したデータをクライアント側で使い回すこと。キャッシュの利点はサーバとクライアント間の通信を減らすことでネットワーク帯域の利用や処理時間を縮小できること。ただ古いキャッシュを使用してしまい、情報の信用性が下がる危険もある。

統一インターフェース

次のアーキテクチャスタイルは統一インタフェース。統一インタフェースとはURIで示したリソースに対する操作を統一した限定的なインタフェースで行うこと。例えばHTTP1.1ではGETやPOSTなど8個のメソッドだけが定義されており、通常はこれ以上メソッドは増えない。一般的なプログラミング言語の感覚からすると厳しい制約だが、このおかげでアーキテクチャがシンプルになる。またインタフェースを統一することで、クライアント・サーバの実装の独立性が向上。

階層化システム

統一インタフェースの利点の一つにシステム全体を階層化しやすいことがあげられる。webサービスではサーバとクライアントの間にプロキシを設置してアクセス制限したりするが、クライアントからするとサーバもプロキシも同じインタフェースで接続できるので、接続先がサーバからプロキシに変わったことを意識する必要がない。基幹系のレガシーシステムでHTTPのインターフェスを実装してないシステムでも、レガシーシステムの前にWEBサーバを挟めばブラウザなどのクライアントと接続できるようになる。 このようにシステムをいくつかの階層(サーバ/プロキシ/クライアント)に分離するアーキテクチャスタイルを階層化システムという。

コードオンデマンド

コードオンデマンドとは、プログラムコードをサーバからダウンロードし、クライアント側でそれを実行するアーキテクチャスタイル。javascriptやflashなどがこれに該当する。この利点はクライアントを後から拡張できること。クライアントプログラムに予め用意した機能以外も使うことができる。 欠点はネットワーク通信におけるプロトコルの可視性が低下すること。HTTPというアプリケーションプロトコルに従って通信している時は通信の意味やアクセスするリソースが明白だが、クライアント側でコードをダウンロードして実行すると、可視性は低下する。

RESTまとめ

RESTは以下の6つを組み合わせたアーキテクチャスタイル。 クライアント/サーバ キャッシュ ステートレス コードオンデマンド 統一インタフェース 階層化システム REST以外にもP2Pといったアーキテクチャスタイルがあり、サーバを介さずに通信したい時とかはRESTよりもこっちの方が良かったりする。

RESTの2つの側面

RESTとハイパーメディア

web上のリソース同士が持つリンクをたどる作業をいくつか経ることで、ソーシャルブックマークという一つのアプリケーションが誕生するような特徴を、RESTでは「アプリケーションエンジンとしてのハイパーメディア」と呼ぶ。アプリケーション状態とは「ブックマーク一覧を表示している」「新しいブックマークを追加しようとしている」といった具体的な状態。アプリケーション状態はハイパーメディアのリンクを辿ることによって遷移するため、ハイパーメディアがアプリケーション状態エンジンと呼ばれる。 リソースをリンクで接続することで一つのアプリケーションを構成するという考え方はRESTの基幹をなす思想。この考えを「接続性」と呼ぶ。

RESTと分散システム

RESTに基づいたWEBサービスはリンクを辿ることでアプリケーションを実現する。リソースはそれ自体で意味を持つ一塊のデータであり、RPCのような分散オブジェクトが呼び出す関数のようなデータよりも粒度が大きい。 またRPCや分散オブジェクトではバージョンアップするたびに、メソッドが増えたり因数や戻り値が変わったりしてAPIの互換性が失われる。一方RESTに基づいたWEBでは統一インタフェースによってこの問題が起こらない。

URI

URIを構成するパーツは以下の通り。 URIスキーム:http ホスト名:blog.example.jp パス:/entries/1 ホスト名はドメイン名またはIPアドレス 以下のような複雑なIPアドレスもある。 URIスキーム:http ユーザ情報:yohei:pass ホスト名:blog.example.jp ポート番号:8000 パス:/serch クエリパラメータ:q=test&debug=true URIフラグメント:#n10 ユーザ情報はリソースにアクセスするためのユーザ名とパスワードから成り立つ。ホスト情報はホスト名とポート番号から成り立ち、ポート番号はこのホストにアクセスするときのプロトコルで用いるTCPのポート番号を示す。ポート番号を省略した場合は各プロトコルのデフォルト値が用いられる。 クエリパラメータはクライアントから動的にURLを生成するときに用いる。 URIフラグメントはURIが指し示すリソース内部のさらに細かい部分を特定するときに使用。この例がhtml文書の場合はid属性がn10であることを示す。

相対URIと絶対URI

ルート(1番上のディレクトリ)から記述したパスを絶対パスという。相対パスは現在のディレクトリから書く。外部サイトには相対URIを書くことができない。相対URIを使えばドメインを変えても問題が起きないというメリットがある。 相対URIの起点となるURIを指定するのがベースURIである。

URIと文字

URIで使える文字は決まっている。日本語を使いたい時は%エンコーディングを使う。%エンコーディングは文字エンコーディング(UTF8など)によって同じ文字でも異なる。

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

クライアントで相対URIを解決するのは大変なので、なるべく絶対URIを使った方がクライアントに親切。 URIに日本語とかを入れるときは%エンコーディングの文字コーディングとしてUTF8が望ましい。 URLとURLを総称する名前がURI。URLはサーバが障害で変更になったりするとアクセスできないが、これを解決するためにドメイン名と独立してリソースに恒久的なIDを振った結果がURN。ただURNはそんなに普及してない。理由はURLが十分永続的なのと、URNはURIとしてリソースを取得できないから。

URIの設計

クールなURIは変わらない。

URIを変わりにくくするには

・プログラミング言語に依存した拡張子やパスを含めない:ある言語に依存した文字列をURLに含めるとその言語を変更した途端そのURLは使えなくなる。 ・メソッド名やセッションIDを含めない:メソッド名を変更した途端にURIが変更になってしまう。セッションIDをCookieではなくURIに埋め込んではいけない。なぜならセッションIDはログインするたびに変わるから。 ・URIはリソースを表現する名詞にする:URIとHTTPメソッドの関係は動詞と名詞の関係にある。URIは全体として名詞になる必要がある。最近はRubyとかでは実装に依存したURIはデフォルトでは作られないようになっている。

URIのユーザビリティ

シンプルなURIは覚えるのも簡単。間違いにくい

URIを変更したいとき

リダイレクトを使う

URI設計のテクニック

拡張子で表現を指定する。プログラミン言語を指定するのはまずいが、自然言語や(htmlかjson)とかを指定する分には良い。 httpにはコンテントネゴシエーションという機能があり、日本語版のOSを使っている人には日本語、英語版のOSを使っている人には英語を返せる。(Acceptヘッダを使用。他にもacceptヘッダで文字エンコーディングやメディアタイプを指定できる)コンテントネゴシエーションがある場合は日本のOSから英語のリソースを取ってくるにはブラウザの設定を変更しないといけないが、拡張子で言語を明示すればその問題は消える。 階層構造で表すことができず、複数パラメータの組み合わせで表現するようなリソース(マップなど)はマトリクスURIで示す。マトリクスURIでは/ではなく;や,で区切る(p62)

Http

インターネットのネットワークプロトコルは階層的。 ネットワークインターフェース層:物理的なケーブルやネットワークアダプタ。(ex イーサネット) インターネット層:ネットワークでデータを実際にやりとりする部分(IP)。IPではデータの基本単位をパケットと呼ぶ。IPではデータを送り出すことだけを保証。送り出したデータが送り先に届くかは保証しない。 トランスポート層:データの転送を保証する(TCP)。TCPは接続先の相手に対してコネクションを貼り、データの到達を保証。TCPで接続して転送したデータがどのアプリケーションに渡るかを決定するのがポート番号。https://www.infraexpert.com/study/tcpip.html アプリケーション層:具体的なアプリケーション(メールやHTTP)を実現する層。TCPでプログラムを作るときはソケットと呼ばれるライブラリを使うのが一般的。ソケットはネットワークでのデータのやりとりを抽象化したAPIで、HTTPサーバやブラウザはソケットを用いて実装。

HTTPのバージョン

HTTP0.9が最初のHTTP。WEBが発明されたときに使われていたプロトコルのこと。ヘッダはなく、メソッドもGETしかない。 HTTP1.0はIETFで最初に標準化が行われたバージョンのこと。GET以外のメソッドの追加、ヘッダの導入などが行われる。 HTTP1.1でHTTPが完成する。チャンク転送、ACCEPTヘッダ、複雑なキャッシュコントロールなどが導入。

リクエストとレスポンス

サーバでの処理に時間がかかる場合でもクライアントはレスポンスが帰るまで待機。 リクエストとレスポンスの例。 クライアントはまずDNSを使ってドメイン名を名前解決(「ドメインネーム」を「IPアドレス」に変換する)し、その結果得られるIPアドレスを使ってTCP80番ポートに接続して、リクエストを送信。 サーバーはこのリクエストを読み取ってレスポンスを返す。 サーバから帰ってきたレスポンスを解析した結果、再度リクエストが必要になる場合もある。画像やスタイルシートへのリンクがいくつも含まれている時とかは、正しくHTMLをレンダリング(データ記述言語やデータ構造で記述された抽象的で高次の情報から、コンピュータのプログラムを用いて画像・映像・音声などを生成すること)するためには50回以上リクエストを発行しないといけない。 クライアントからリクエストを受けたサーバはまずリクエストメッセージを解析し、クライアントがトップページの取得を要求していると知ったとすると、トップページのHTMLをレンダリングするアプリケーションに処理を委譲し、結果のHTMLを取得。その後適切なヘッダを付加してレスポンスを返す。

HTTPメッセージ

リクエストメッセージ

リクエストメッセージの1行目は、リクエストラインと呼ばれる(p77を参照すること) リクエストURIに絶対URIを用いた場合はリクエストラインの次にHostヘッダを書く必要がない。 リクエストメッセージの2行目以降はヘッダが続く。ヘッダの後にはボディがくることもある(リソースを更新したりする場合)。

レスポンスメッセージ

レスポンスメッセージの1行目はステータスライン。プロトコルバージョン(HTTP/1.1),ステータスコード(200),テキストフレーズ(OK)からなる。ステータスコードはリクエストの結果(200,404・・)を示す。 レスポンスメッセージの2行目はヘッダ。Content-Typeヘッダなどがある。 ボディが含まれることもある。ヘッダとボディの間には空行があり。

HTTPメッセージの構成要素

1行目はスタートライン(リクエストラインorステータスライン) スタートラインの次はヘッダ。ヘッダの終了は空行で示す。ヘッダは省略可能。 ヘッダの次はボディ。ボディも省略可能

ステートレス

アプリケーション状態はセッション状態ともいう。システムにログインしてからログアウトするまでの一連の操作をまとめてセッションという。 ステートフルの代表的なプロトコルがftp。 ステートフルの欠点は①クライアントが増えるとサーバがクライアントのアプリケーション状態を覚えるのが大変②クライアントが増えるとサーバを増やす必要があるが、クライアントがどのサーバに接続するか特定できないので、サーバ間でアプリケーション状態を同期する必要があり、この際のオーバーヘッド(間接的なコスト)が問題になる。 ステートレスのメリットはサーバ側の仕組みが単純なこと。デメリットはクライアントから送信する情報が多くなることと、認証などのサーバに負荷がかかる動作を繰り返すこと(認証でデータベースにアクセスするとかは思い処理と言える)。また通信エラーの時の対処も問題になる。なぜならサーバーはアプリケーション状態を覚えてないので、通信障害時にリクエストが処理されたか分からないから。(p86)

httpメソッド

CRUDとはcrete,read,update,deleteの略。HTTPメソッドはget,post,put,delete,head,options,trace,connectの8つ。

POST

POSTでは子リソースの新規作成ができる。また新規作成ではなくデータの追加も可能。POSTの挙動が作成か追加は実装に依存するので、WEB APIの仕様書とかを確認すること。 POSTでは他のメソッドで対応できない処理の実行も可能。(p93)https://www.iruca21.com/entry/2017/03/16/152616

PUT

PUTの機能はリソースの内容の更新とリソースの作成です。PUTはURIを指し示すリソースを直接を指定するが、POSTは子リソースのURIをサーバを勝手に作成するという違いがある。https://hajimehoshi.hatenadiary.org/entry/20090710/1247161012 リソース作成における、PUTとPOSTの使い分けに正解は存在しないが、設計の指針として以下の事実がある。POSTでリソースを作成する場合、クライアントはリソースのURIを決められないが、PUTの場合は逆。 twitterのように呟きのURIをサーバが自動で決定するような場合はPOST。Wikiのようにクライアントが決めたタイトルがURIになる場合はPUT。この場合はURIの上書きを避けるためにクライアントが事前にURIをチェックする必要があるかもしれない。

HEAD

HEADはリソースのヘッダだけを取得する。つまりボディが含まれない。ネットワークの帯域を節約しながらリソースの大きさや更新日時を取得するのに使う。

OPTIONS

OPTIONSはそのリソースがサポートしてるメソッドの一覧を返す。 OPTIONSを実装する場合は、多くのウェブフレームワークでは自分で実装する必要がある。

POSTでPUT/DELETEを代用する方法

HTMLのフォームで使用できるのはGETとPOSTだけ。ただ_methodパラメータを用いるとHTMLフォームでもPUTとか使える。http://portaltan.hatenablog.com/entry/2015/07/22/122031 _methodパラメータはフォームを使ってリクエストを送らない場合(POSTの内容がXMLなど)時は使えない。その場合はX-HTTP-Method-Overrideヘッダを使用する

条件付きリクエスト

HTTPメソッドと更新日時などのヘッダを組み合わせることで、メソッドを実行するかどうかをリソースの更新日時を条件にサーバが選択できるようになる。これを条件付きリクエストという。

べき等性と安全性

べき等は操作を何回やっても結果が同じことを表す(GET,HEAD,PUT,DELETE) 安全性は操作対象のリソースを変化させないこと(GET,HEAD) POSTはべき等でも安全でもないから、二重注文とかが起こる。 GETメソッドを使ってdeleteを行う(p105)とかをするのは駄目。 POSTがなんでもできるからといって、GET,PUT,DELETEとかの機能をPOSTで行おうとしたら駄目。 PUTで現在のリソースとの差分(+50とか)を送信するとべき等でなくなってしまうから注意。 DELETEがべき等でなくなるのはlatestとか使って表されたURIを削除するとき。これを防ぐために、時間や状況で指し示すリソースが変化するリソースは更新や削除ができないようにする

ステータスコード

1xx:処理中 2xx:成功 3xx:リダイレクト 4xx:クライアントエラー。クライアントのリクエストに問題がある 5xx:サーバーエラー。サーバー側に問題があるので、その問題が解決すれば、同一リクエストで正常な結果が得られる可能性がある。 未知のステータスコードが来た場合も、100の位が守られてればクライアントは最低限の処理ができる。

よく使われるステータスコード

200ok:リクエスト成功 201created:リソースの作成成功 301MovedParmanently:リソースの恒久的な移動。リソースが新しいURIに移動したことを示す。新しいURIはレスポンスのlocationヘッダに絶対URIとして入る。 303SeeOther:別のURIの参照。リクエストに対する処理結果が別のURIで見れることを示す。(POSTでログイン情報を送った後に、ユーザーページのURIを返す時など。) 400BadRequest:リクエストの間違い。リクエストしたパスワードが単純すぎる時など。 401Unauthorize:アクセス権不正。WWW-Authenticateヘッダでクライアントに対して認証方式を伝える。 404notfound:リソースの不在 500InternalServerError:サーバ内部エラー。 503ServiceUnavailable:サービス停止。サーバがメンテナンス中の時とか。 クライアントがアクセプトヘッダでhtml形式とかxml形式とかを指定している場合は、それに応じてエラーメッセージを動的に変更できる。

ステータスコードの誤用

p123参照。GETしたいファイルが見つからないというエラーを200OKで返したりしているものがある。

HTTPヘッダ

リソースへのアクセス権を設定する認証や、クライアントとサーバの通信回数を減らすキャッシュの機能とかはヘッダで実現。 HTTPの使用は電子メールのメッセージ使用のヘッダ形式を参考に作られているので、ヘッダの詳細を知るには電子メールの仕様を知らなければならない。 電子メールのヘッダには7bit ASCIIコード以外の文字を入れないという制約があり、HTTPヘッダもそれを引き継いでいる。以下代表的なヘッダ。p123以降参照。 日時:DateやExpiresが相当する。日時は全てGMT(グリニッジ天文台)で記述。 MIMEメディアタイプ:リソースの表現の種類を指定。content-typeはapplication/xhtml+xmlみたいにメディアタイプを指定するやつ。/の左がタイプ(text,imageなど)で右がサブタイプ。 charsetパラメータは文字のエンコーディングを指定。省略可能だが、タイプがtextの時は色々と不具合が起こりやすいから注意。textタイプの時は必ずcharsetを指定し、かつtext/xmlという形式は使わずapplication/xmlとかを使うと問題は起こらない。 言語タグ:content-languageヘッダは自然言語を指定。ja-JPなどといった書き方で左がISO639が定義する言語コードで右がISO3166が定義する地域コード。

コンテントネゴシエーション

クライアントが自身が処理できるメディアタイプの順位をサーバに伝える。 Accept:処理できるメディアタイプを伝える。サーバがそのメディアタイプに対応してない時は406NotAcceptableが帰る。 Accept-Charset:処理できる文字エンコーディングを伝える。 Accept-Language:処理できる言語を伝える。

Content-length:ボディの長さを指定。静的なファイルなどあらかじめサイズの分かってるリソースを転送する場合に使うと良い。
チャンク転送:動的に画像を生成するようなWebサービスの場合、ファイルサイズが決まるまでレスポンスを返せないのでは応答速度が悪くなる。この時はTransfer Encodingヘッダにchunkを指定して、最終的なサイズが分からないボディを少しずつ転送できるようになる。

認証

HTTP認証方式にはBasic認証とDigest認証がある。WWW-Authenticateヘッダによりクライアントはサーバが提供する認証方式を理解できる。 Basic認証はユーザー名とパスワードによる認証方式。Authorizationヘッダの内容はユーザ名とパスワードをBase64エンコードしたものになる。Base64円コーディングは簡単にデコード可能だから、SSL、TLSを使ってHTTPS通信し、通信路上で暗号化したほうが良い。 Digest認証はBasic認証よりも安全。流れとしては、まず認証情報なしでリクエストを送ると認証が失敗し401 Unauthorizeが帰ってくる。この時のwww-Authenticateヘッダにはまずnonceというリクエストごとに変わる文字列が入っている。qopという値も入っていて、この値がauthかauth-intかによってダイジェストの作成方法が変わる。https://ken3ypa.hatenablog.com/entry/2019/01/10/212124 https://ja.wikipedia.org/wiki/Digest認証 Digest認証ではBasic認証と違いパスワードを盗まれ危険がない。Digest認証ではサーバ上にパスワードのハッシュ値を補完しておけば良いのでパスワードそのものをサーバに預けずに済むので安全。https://blog.goo.ne.jp/xmldtp/e/b6a697735a597e8e41af460ae2f2875a Digest認証の場合もパスワード以外は平文でネットワークを流れるので、メッセージを暗号化したい場合はHttpsを使う。 Basic認証の場合は同じURI空間にあればクライアントは一度認証すれば2回目以降は自動でユーザとパスワードを送れる。Digest認証の場合はサーバからのnonceが毎回必要なので、リクエストの度に401レスポンスを得ることになり面倒。Digest認証がサポートされてないサーバーもある。

OpenIDとOAuth

OpenIDを使うとYahooのアカウントで自分が開発したサイトにもアクセスできるようになったりする。 OAuthはwebサービス間でデータをやり取りできるようにするための仕様。あるサービスに保存してある写真を他のサービスでも使えるようにすることを認めるもの。

WSSE認証

HTTP1.1の標準外の認証方式。AtomPubなどのWeb APIの認証に使われる。BASIC認証もDIGEST認証も使えない場合に、パスワードを盗まれずに送信するための方法。この認証方式は生のパスワードをネットワークに流さずにすむうえDigest認証ほどめんどくさくない。一方サーバ側で生のパスワードを保存しておく必要がある。

キャッシュ

クライアントはローカルストーレージにキャッシュを蓄積する。クライアントが蓄積したキャッシュはそのキャッシュが有効な間、クライアントが再度そのリソースにアクセスしようとしたときに再利用する。リソースがキャッシュ可能かその有効期限がいつまでかは、ヘッダを用いてサーバが指定。キャッシュのためのヘッダにはいくつかある。使い方の方針としては, キャッシュをさせない場合はPragmaとCashe-Controlのno-casheを同時に指定。キャッシュの有効期限が絶対的に決まっている時はExpieresを指定。有効期限を相対的(今から〜時間)に決める時はCasheーcontrollのmax-ageを使用。 ローカルキャッシュが期限切れで使えないとクライアントが判断した場合でも、リソースがLast-ModifiedヘッダかETagヘッダを持っている場合は、条件付きGETを使用してサーバのリソースがクライアントのローカルキャッシュから変更されているかを調べて、キャッシュを再利用できるか判断できる。 ETagヘッダの方がおすすめp148。

持続的接続

HTTP1.0ではクライアントがTCPコネクションを確立してリクエストを送信し、サーバーがそれにレスポンスを返すたびにTCPのコネクションを切断していた。TCPのコネクション確立はコストがかかる処理なので、画像とかにたくさんリンクしているページを表示させようとするともっさりした動作になった。これを避けるためにkeep-aliveヘッダでサーバとクライアントが常に接続状態であるようにした。この持続的接続状態ではクライアントはサーバのレスポンスを待たずにリクエストを送信できる。これをパイプライン化という。

HTML

構造化文書のためのマークアップ言語としてはSGMLがあった。HTMLはSGMLを元に作られた。SGMLでは複雑で処理プログラムが作りにくかったので、仕様をシンプルにしたXMLが開発された。HTMLをSGMLベースからXMLベースに変えた仕様がXHTML。

メディアタイプ

HTMLのメディアタイプにはtext/htmlとapplication/xhtml+xmlの2種類がある。前者はSGML形式のHTML、後者はxmlベースのXHTMLを示す。 htmlは木構造になっていて親要素・子要素の関係にある。 内容を持たないから要素がある
など。これは
と省略できる。 要素は属性を持つことができる。属性名=”属性値”という書き方。 「<」とかは特殊文字だから<と表記する。 名前空間:複数のHTMLフォーマットを使うときに名前の衝突を防ぐために使うのが名前空間。属性の名前空間や要素の名前空間とかがある。https://www.cybertech.co.jp/xml/contents/xmlxmldb/serial/_xmlbeginner10.php#title4 名前空間がついた属性をグローバル属性という。ついてないのをローカル属性という。

htmlの要素

ヘッダに入る要素 title link:他のリソースへのリンク script:javascriptなどのクライアントサイドプログラム meta:その他のメタデータ がある。 HTMLの全ての要素はid属性とclass属性を持つことができる。 要素は他のページにリンクするために使う。a href~ 要素はHTMLのヘッダでwebページ同士の関係を指定するために使う。 画像の埋め込みには、それ以外の埋め込みには要素を使用

microformats

htmlの中でさらに意味のあるデータを表現するための技術がmicroformats。 昔からRDFをベースとしたセマンティックWebがWeb上の情報に意味を与えるとされてきたが、現在使われてるRDFのアプリケーションはほとんどない。microformatsはそんな夢のような技術であるセマンティックWebを地に足のついた方向に導く。https://qiita.com/maoringo/items/4742b5cd01c9e698260d セマンティックなWEBとは人間だけでなく、プログラムもHTMLに書かれている内容を理解できるようにすること。 RDFの問題点は記述が複雑。統一的な記述がしづらい。対象データとは独立したメタデータ。 RDFの問題点を解消したのがmicroformats。microformatsは元のHTML文書に必要最低限の情報を追加するだけp177。 このようにmicroformatsはhtml文書にメタデータを埋め込む技術。現在メタデータの標準化が進んでるp179 microformatsには、elemental microformats(rel-lisenceのようにリンク関係を使ってメタデータを表現するフォーマット)とcompoud microformats(主にclass属性を使って階層構造のあるメタデータを表現するフォーマット)の二つがある。

elemental microformats

・rel-licence:リンクの参照先が参照元のページのライセンス情報であることを示す ・rel-nofollow:スパムリンクを禁止する

compoud microformats

・hCalendar:カレンダー情報、イベント情報をclass="summary"みたいな属性をつけて示す。 ・hAtom:Atomが持つメタデータを記述。

microformatsの問題点

microformatsはclassやrel属性の値だけでメタデータを特定するので、もし同じ値のclassやrel属性を持ったwebページがあった場合、プログラムが誤判定を起こす。この問題を解決するためにW3Cが進めているのがRDFaの標準化。xmlの名前空間を使用して衝突を回避。ただこれをするとプログラムが複雑化する。mたxmlの名前空間を利用しているのでXHTMLでしか使えず、htmlでは使えない。

リソースの表現としてのmicroformats

プログラム用にjsonやAPIを別に提供するスタイルには以下の問題点がある。 webサービスとweb APIで提供する機能が異なってしまいがち。開発規模の増大に伴うメンテナンス性の低下。WEB APIに必要な技術の取得コスト。 microformatsを使えばwebページをそのままAPIとして提供できるというメリットがある。Web APIとWEBサービスを分けないという考え方は,Web APIとWEBサービスの設計においてとても重要。

Atom

Atomはブログなどの更新情報を配信するためのフィードとして知られているが、実際は幅広い分野での応用が可能な汎用XMLフォーマット。https://www.sixapart.jp/about/feeds.html

Atomのリソースモデル

Atomの論理モデルは、メンバリソースとメンバリソースを複数含むコレクションリソースの二つに分かれる。 メンバリソースはAtomにおける最小のリソース単位。ブログであれば一つ一つの記事がメンバリソースになる。メンバリソースはXMLで表現できるエントリリソースとそれ以外のメディアリソースに分かれます。エントリリソースは例えばブログ記事本文やそれに対応する日時、筆者などがまとまった、テキストやXMLで表現できるリソース。エントリリソースは要素で表現。 メディアリソースは画像や映像などテキスト表現できないリソース。p189 コレクションリソースは複数のメンバリソースを含むリソース。要素で表現。 Atomのメディアタイプはapplication/atom+html。拡張子は.atom。 atomPubと組み合わせるとリソースの表現だけでなく、HTTPを活用した操作もできるようになる。

AtomPublishingProtocol

Atomはデータフォーマットの規定。Atom PubはAtomを利用したリソース編集プロトコルの規定。 Atom Pub以前にもブログを編集するためのプロトコルはあったが、国際性や拡張性に問題があるAPIだった。Atom Pubは汎用的なWeb Apiの基礎をなすプロトコルとしての素質を備えている。 AtomPubの規定に従って、Atomのフォーマットを編集(update)したりするイメージ。p220 Atom Pubでは内容を編集した場合は編集していな部分も含めて丸ごとサーバに送信する。updatedの日付とかはクライアントではなく、サーバーが設定する。

メディアリソースの操作

メディアリソースはエントリではなく画像ファイルになる。要素のXML文書では画像本体を送ることはできない。この場合はメディアリソースの画像本体をPOSTする。p222

サービス文書

コレクションリソース(ユーザごと、月ごととかで分類されてる)のリストを集めたものがサービス文書。

AtomPubに向いてるWeb Api

AtomPubはタイトルや更新日時といった基本的なメタデータを持ったリソースであるエントリをCRUDするWEB APIのためのプロトコル。AtomPubに向いてるAPIは、ブログ、検索機能を持つデータベース、マルチメディアファイルのリポジトリ、タグを使ったソーシャルサービス。 向いてないのは、リアルタイム性が重要なAPI、映像のストリーム配信などHTTP以外のプロトコルを必要とするAPI、データの階層構造が重要なAPI、タイトル、作者などが不要なAPI。

JSON

ここまではHTML、microformats,AtomというXML系のリソース表現を解説してきた。JSONはXMLのように文書をマークアップするのには向いてないがプログラミング言語から扱いやすいデータ構造を記述できる。 JSONはjavasxriptの記法で表現できる。ブラウザがjavascriptを実行できること、XMLと比べてデータ表現の冗長性が低いことからAJAX通信で重宝されてる。

jsonpによるクロスドメイン通信

jsonでリソースを表現する副次的効果としてjsopを利用できることがある。ajaxで用いるXMLHttpRequestというjavascriptのモジュールはセキュリティ上の制限からjavascriptファイルを取得したのと同じサーバとしか通信できない。javascriptがあるサーバとは別のサーバと通信できるとブラウザで入力した情報をユーザが知らない間に不正なサーバに送信できてしまう。しかしこの場合だと自サービスでは地図データと郵便番号データを保持せずに、それらを提供してる他のWEBAPIから取得するといったことができない。しかしHTML通信のscript要素を使えば複数のサイトからjavascriptファイルを読み込める(script要素は歴史的理由で通常はブラウザのセキュリティ制限を受けない)。jsonpはこの性質を利用してクロスドメイン通信(複数のサーバとやりとり)を行う手法。

WEBサービスの設計

ここではリソース設計を扱う。リソース設計はクライアントとサーバ間のインタフェースの設計。つまりWEBサービスの外部設計。 リソース設計の指針はあまり存在しないが一応以下のようなものがある。 WEBサービスで提供するデータを特定→データをリソースに分ける(1番難しく重要な工程)→(各リソースに対して以下を実行)→URIで名前をつける→クライアントに提供するリソースの表現を設計→リンクとフォームを利用してリソース同士を結びつける→イベントの標準的なコースを検討→エラーについて検討 p244の内容を同リソース設計するか考えると良い。リソース設計ではアドレス可読性→接続性→統一インタフェース →ステートレス性の順で大事。 機能(検索機能など)は情報とは言えない。機能をリソースに落とし込むには、機能の結果をリソースとして捉えることが重要。

書き込み可能なWebサービスの設計

一般的にはリソースの作成にはPOSTを使うのが無難だが、PUTで作成する場合は、POSTをサポートしなくても済むのでサーバの実装が楽。クライアントが作成と更新を区別しなくて済むからクライアントの実行が楽。ただクライアントがURI構造をあらかじめ知っていないといけない、リクエストの見た目上はその操作が更新か作成かわからないというデメリットもある。 リソースの更新にはバルクアップデート(更新してない部分もまとめ更新)とパーシャルアップデート(変更した部分をピンポイントで更新)の2種類がある。前者はクライアント側の実装は簡単だが、送受信するデータが大きくなる。そのためAjaxなどの非同期通信などで、ユーザからの入力の都度サーバにデータを送信するには不都合。後者の場合は送受信するデータが少なくなる反面、GETしたリソースの一部を修正してそのままPUTするという使い方ができなくなる。よってパーシャルアップデートをサポートする場合はバルクアップデートもサポートするのが望ましい。

リソースの削除

リソースを削除するときは親リソースを削除したら子リソースも削除すること。

バッチ処理

バッチ処理は大量の郵便番号を作成したり更新したりするときに、リクエストを1回1回送っているとパフォーマンスが著しく下がるので、リソースをまとめて一度に送信することを示す。このとき一部の作業だけが失敗したときは、トランザクションを使うか、どのリソースの処理が成功し、どの処理は失敗したのかをクライアントに伝えるかの2通りがある。

排他制御

複数のクライアントを想定したリソースの更新は、同時に一つのリソースを更新して競合が起きないように注意。これを排他制御と言い、悲観的ロックと楽観的ロックの2種類がある。 悲観的ロックはHTTPをwebDavのlock,unlockを利用、もしくはLOCK相当の機能をWEBサービスに組み込むことで実装できる。 悲観的ロックは誰かが編集してる間はロックをかけて他の人が編集できないようにする。この場合は少数のグループ内で運用してるシステムなら誰がロックをかけているのか分かるので問題ないが、不特定多数の人が使うサービスだと誰かがずっとロックしたままにしちゃうみたいな問題が起こる。https://qiita.com/NagaokaKenichi/items/73040df85b7bd4e9ecfc 楽観的ロックは、ロックはかけずに競合が起きた時だけ対処する仕組み。そう頻繁に更新が起きるはずはないという前提に立っている。HTTPで実装するなら条件付きPUTとDELETEを使う。

WEBサービスの設計で重要な項目

なるべくシンプルに保つ:不要な機能は入れない 困ったらリソースに戻って考える:HTTPメソッドで実現できない機能があるとしたら、それが独立したリソースで代替できないか考える。 本当に必要ならPOSTでなんでも実現可能

リソースの設計

リソース設計で大変な「WEBサービスで提供するデータを特定」し「データをリソースに切り分ける」方法にはまだ定石がない。しかし以下のようなものを元にリソースを設計すると良いだろう。①関係モデルのER図②オブジェクト指向のクラス図③情報アーキテクチャ ER図はデータベースの設計。これの中心となってるテーブルの1行を1リソースとすると良い。 最も重要なのはWEBサービスとWEBAPIを分けて考えないこと! https://qiita.com/ksk_lack/items/29c354a80743bae153ac
2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?