Rubyを使ったHTTPサーバーの構築
その記事はもともと投稿されたhere . いくつかのGIFはここに表示されません.
Webサーバーは、ユーザーからあなたのウェブサイトに要求を受け取り、それにいくつかの処理を行うプログラムです.それから、アプリケーション層に要求を与えるかもしれません.最も人気のあるWebサーバのいくつかは、NGinx、Apacheです.(リバースプロキシ、ロードバランシング、その他多くの機能がありますが、主にWebサーバとして動作します).
さて、質問をさせてください.開発中にlocalhostで動作するサーバーは、Webサーバーですか?あなたが送ったどんな要求でも、それを処理して、それから適切なページをロードしてください.したがって、それはWebサーバーのように見えるかもしれないが、より技術的には、それはアプリケーションサーバーと呼ばれています.アプリケーションサーバーは、コードを読み込み、メモリ内のアプリケーションを保持します.あなたのアプリケーションサーバーがあなたのWebサーバからの要求を取得すると、それはそれについてのあなたのアプリを伝えます.あなたのアプリケーションは、要求を処理して行われた後、アプリケーションサーバーは、Webサーバー(そして最終的にはユーザーに応答)を送信します.特にRailsでは、ユニコーン、プーマ、細い、虹のような多くのアプリサーバーがあります.
しかし、コミュニティによってテストされ、数千人で使用されるように多くのサーバーがある場合は、なぜ我々は別の建物を悩ます必要がありますか?さて、ゼロから1つを構築することによって、我々はこれらの作品がどのように良い知識があります.
それで、HTTPサーバが何をするかを壊しましょう.
それで、我々が特定のURLを訪問するとき、それは特定のHTTP要求をサーバーに送ります.さて、HTTPリクエストは何ですか?これは、アプリケーションレベルのプロトコルは、すべてのアプリケーションがインターネットに接続して同意する必要があります.FTP(ファイル転送プロトコル)、TCP(Transmission Control Protocol)、SMTP(Simple Mail Transfer Protocol)のような他の多くのプロトコルがあります.HTTPまたはHyperText Transfer Protocolはこれらの間でちょうど非常に人気があって、ウェブアプリケーションとウェブサーバによって使われます.
つまり、ブラウザでURLを1つ入力するとき.それはウェブサーバにHTTP「リクエスト」を作ります、そこで、ウェブサーバはその要求を処理して、ブラウザーでユーザに提出されるHTTP「レスポンス」を送り返します.
最初のHTTP規格は1996年にティム・バーナー・リーによってHTTP/1.0であった.現在、HTTP/2はHTTPの意味をより効率的に表現しています.また、ウェブサイトの4 %以上で既に使用されているHTTP 3である別の後継者が存在することを知っていましたか
それで、我々はクライアントとサーバーの双方向通信を聞くツールを必要とするでしょう.基本的にソケット.ソケットは双方向通信チャネルのネットワークエンドポイント上で実行されている2つのプログラム間の双方向通信のための終点にすぎない.TCP層がデータが送られるアプリケーションを見つけることができるように、それはポートに縛られなければなりません、サーバーはリスナソケットを形成します、そして、クライアントはソケットに手を差し伸べます.ソケットを実装しません.Rubyには既に標準ライブラリで実装されているソケットがあります.
Webサーバの基本的なプロセスは何ですか 接続を聞く リクエストをパースする プロセスを処理し、レスポンスを送信する
まず、ポートを開いて、特定のポートに送られたすべてのメッセージを聞きましょう.我々はそれを使用することができます
今、私たちは着信接続を処理するために無限ループをしたいです.クライアントがサーバーに接続している場合.
では、次のようになります.
つの端末をオープンし、Rubyスクリプトを起動し、他のオープンで
他の端末では
テストするより簡単な方法は、スクリプトを実行し、ブラウザを使用してそのポートを訪問することです.ポートが
なぜちょうど
リクエストを送信すると、複数行の文字列に解析されます.コマンドを実行します
これまでのところ、
たった今、我々はちょうどストリングとして要求を受けています、我々のサーバーが理解することができて、さらにそれを処理するように、我々はそれを解析する必要があります.
もう一度リクエストを見てみましょう.
方法 パス プロトコル その後のすべての行はヘッダーの下に来る.それで、我々は生の要求ストリングを解析するこの機能を書きます
今、我々はすべてのデータを持っているので、我々は今準備し、応答を送信する必要があります.リクエストのパスがホームを参照している場合は
一旦すべてが適切であるならば、我々は最終的にスクリプトを走らせて、URLを訪問することができます
やあ!我々は正常に独自のHTTPサーバーを構築している
どのようなWebサーバーですか?
Webサーバーは、ユーザーからあなたのウェブサイトに要求を受け取り、それにいくつかの処理を行うプログラムです.それから、アプリケーション層に要求を与えるかもしれません.最も人気のあるWebサーバのいくつかは、NGinx、Apacheです.(リバースプロキシ、ロードバランシング、その他多くの機能がありますが、主にWebサーバとして動作します).
さて、質問をさせてください.開発中にlocalhostで動作するサーバーは、Webサーバーですか?あなたが送ったどんな要求でも、それを処理して、それから適切なページをロードしてください.したがって、それはWebサーバーのように見えるかもしれないが、より技術的には、それはアプリケーションサーバーと呼ばれています.アプリケーションサーバーは、コードを読み込み、メモリ内のアプリケーションを保持します.あなたのアプリケーションサーバーがあなたのWebサーバからの要求を取得すると、それはそれについてのあなたのアプリを伝えます.あなたのアプリケーションは、要求を処理して行われた後、アプリケーションサーバーは、Webサーバー(そして最終的にはユーザーに応答)を送信します.特にRailsでは、ユニコーン、プーマ、細い、虹のような多くのアプリサーバーがあります.
しかし、コミュニティによってテストされ、数千人で使用されるように多くのサーバーがある場合は、なぜ我々は別の建物を悩ます必要がありますか?さて、ゼロから1つを構築することによって、我々はこれらの作品がどのように良い知識があります.
HTTPサーバは実際にどのような動作をしますか?
それで、HTTPサーバが何をするかを壊しましょう.
手順
それで、我々が特定のURLを訪問するとき、それは特定のHTTP要求をサーバーに送ります.さて、HTTPリクエストは何ですか?これは、アプリケーションレベルのプロトコルは、すべてのアプリケーションがインターネットに接続して同意する必要があります.FTP(ファイル転送プロトコル)、TCP(Transmission Control Protocol)、SMTP(Simple Mail Transfer Protocol)のような他の多くのプロトコルがあります.HTTPまたはHyperText Transfer Protocolはこれらの間でちょうど非常に人気があって、ウェブアプリケーションとウェブサーバによって使われます.
つまり、ブラウザでURLを1つ入力するとき.それはウェブサーバにHTTP「リクエスト」を作ります、そこで、ウェブサーバはその要求を処理して、ブラウザーでユーザに提出されるHTTP「レスポンス」を送り返します.
歴史
最初のHTTP規格は1996年にティム・バーナー・リーによってHTTP/1.0であった.現在、HTTP/2はHTTPの意味をより効率的に表現しています.また、ウェブサイトの4 %以上で既に使用されているHTTP 3である別の後継者が存在することを知っていましたか
どうやって始めるの?
それで、我々はクライアントとサーバーの双方向通信を聞くツールを必要とするでしょう.基本的にソケット.ソケットは双方向通信チャネルのネットワークエンドポイント上で実行されている2つのプログラム間の双方向通信のための終点にすぎない.TCP層がデータが送られるアプリケーションを見つけることができるように、それはポートに縛られなければなりません、サーバーはリスナソケットを形成します、そして、クライアントはソケットに手を差し伸べます.ソケットを実装しません.Rubyには既に標準ライブラリで実装されているソケットがあります.
require "socket"
ソケットライブラリは、一般的なトランスポートを扱うための特定のクラスと、残りを処理するための汎用インターフェイスを提供します.基本的には、OSレベルと対話し、必要な動作を実行します.Webサーバの基本的なプロセスは何ですか
1 .接続をリッスンする
まず、ポートを開いて、特定のポートに送られたすべてのメッセージを聞きましょう.我々はそれを使用することができます
TCPServer.new
or TCPServer.open
メソッド.[医者によると、彼らは同義だ]require "socket"
server = TCPServer.new("localhost", 8000)
Feel free to choose any port, but make sure it is available. Use the command "netstat -lntu" to look for the ports that are currently used by a process, don't use those.
今、私たちは着信接続を処理するために無限ループをしたいです.クライアントがサーバーに接続している場合.
server.accept
は他のRuby I/Oオブジェクトと同様に使用できるRubyソケットを返します.接続が要求によってなされたので、我々はまた、我々が使うことができるその要求を読むのが好きですgets
メソッド.リクエストの最初の行を返します.では、次のようになります.
require "socket"
port = (ARGV[0] || 8000).to_i # to get a port from the ARG
server = TCPServer.new("localhost", 8000)
while (session = server.accept)
puts "Client connected..."
puts "Request: #{session.gets}"
end
これのテスト方法?つの端末をオープンし、Rubyスクリプトを起動し、他のオープンで
irb
. では、以下のコマンドに従ってください.他の端末では
> require "socket"
> soc = TCPSocket.open("localhost", 8000)
> soc.puts "Hello There"
テストするより簡単な方法は、スクリプトを実行し、ブラウザを使用してそのポートを訪問することです.ポートが
8000
ジャスト訪問http://localhost:8000
. 次のようになります.Client connected...
Request: GET / HTTP/1.1
または、curlコマンドを使用することもできます.なぜちょうど
GET / HTTP/1.1
?リクエストを送信すると、複数行の文字列に解析されます.コマンドを実行します
curl -v localhost:8000
次のようになります.* Trying ::1:8000...
* Connected to localhost (::1) port 8000 (#0)
> GET / HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/7.74.0
> Accept: */*
>
そして我々のスクリプトでsession.gets
入力としてIOストリームの1行だけをとります.では、次のように置き換えましょうreadpartial(2048)
. ここで、2048は我々が読むのが好きであるデータのバイトを表します.我々はそれを増やすことができます、しかし、我々のケースのために、それは十分です.これまでのところ、
require "socket"
port = (ARGV[0] || 8000).to_i
server = TCPServer.new("localhost", 8000)
while (session = server.accept)
puts "Request: #{session.readpartial(2048)}"
end
スクリプトとcurlコマンドを再び実行します.HTTPリクエストデータの全てを出力します.HTTPリクエストの解析
たった今、我々はちょうどストリングとして要求を受けています、我々のサーバーが理解することができて、さらにそれを処理するように、我々はそれを解析する必要があります.
もう一度リクエストを見てみましょう.
GET / HTTP/1.1 # GET is the method, the / is the path, the HTTP part is the protocol
Host: localhost:8000 # Headers
User-Agent: curl/7.74.0
Accept: */*
最初の行はdef parse(request_string)
method, path, version = request_string.lines[0].split
{
method: method,
version: version,
path: path,
headers: parse_headers(request_string),
}
end
もう一つparse_headers
ヘッダをパースするにはdef normalize(header)
header.tr(":", "").to_sym
end
def parse_headers(request)
headers = {}
request.lines[1..-1].each do |line|
return headers if line == "\r\n"
header, value = line.split
header = normalize(header)
headers[header] = value
end
end
今すぐリクエストの印刷だけではなく、この方法を行うserver = TCPServer.new("localhost", 8000)
while (session = server.accept)
ap parse(session.readpartial(2048))
end
使用中awesome_print
データをフォーマット形式で表示するには、puts
. 今、あなたはこのようなものを得るでしょう.3 . HTTPレスポンスの処理と送信
今、我々はすべてのデータを持っているので、我々は今準備し、応答を送信する必要があります.リクエストのパスがホームを参照している場合は
index.html
それが他の何かであるならばlocalhost:8000/about.html
その後、我々はそのパスで対応しますabout.html
.def prepare(parsed_req)
path = parsed_req[:path]
if path == "/"
respond_with("index.html")
else
respond_with(path)
end
end
何respond_with
ファイルが存在しているかどうかをチェックすることになっています.def respond_with(path)
if File.exists?(path)
ok_response(File.binread(path))
else
error_response
end
end
応答のために、我々はこの形式のストリングを送ります.http specに従っています.http specについてもっと読むことができますhere .def response(code, body="")
"HTTP/1.1 #{code}\r\n" +
"Content-Length: #{body.size}\r\n" +
"\r\n" +
"\#{body}\r\n"
end
それで我々はok_response
and error_respnse
以下のようになります.def ok_response(body)
MyServer::Response.new(code: 200, body: body)
end
def error_response
MyServer::Response.new(code: 404)
end
今私たちの応答をした後、クライアントに送信することができます.コードをリファクタリングしたので、ここでコード全体を見つけることができます.一旦すべてが適切であるならば、我々は最終的にスクリプトを走らせて、URLを訪問することができます
http://localhost:8000
それはすべてのコンテンツをレンダリングしますindex.html
. 閉じるこの動画はお気に入りから削除されていますabout.html
訪問http://localhost:8000/about.html
も同様にレンダリングされます.やあ!我々は正常に独自のHTTPサーバーを構築している
Reference
この問題について(Rubyを使ったHTTPサーバーの構築), 我々は、より多くの情報をここで見つけました https://dev.to/arnabsen1729/building-http-server-with-ruby-17adテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol