Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
サーバーフレームワークの仕組みが気になったので車輪の再発明をしてみた
Search
Yuta Tomiyama
March 12, 2022
Programming
250
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
サーバーフレームワークの仕組みが気になったので車輪の再発明をしてみた
2022/03/12 全国学生エンジニア交流会「NSEEM」にて発表
https://github.com/yt8492/NativeServer
Yuta Tomiyama
March 12, 2022
More Decks by Yuta Tomiyama
See All by Yuta Tomiyama
ビルドプロセスをデバッグしよう!
yt8492
2
480
モバイルアプリ開発を始めよう!
yt8492
0
120
Git勉強会
yt8492
0
210
なんでもやってみる勇気
yt8492
0
140
Android Autoが思ったよりしんどい話
yt8492
0
250
apollo-kotlinにcontributeした話
yt8492
0
190
DMM TVのSDカードダウンロード機能を実装した話
yt8492
1
1k
今だからこそ知りたいKotlin Multiplatform
yt8492
0
340
State management and API calls in Jetpack Compose: Learning Apollo + Jetpack Compose through React Hooks
yt8492
0
1.4k
Other Decks in Programming
See All in Programming
Javaの型とAI時代に型が大事な理由 / java types and type in AI era
kishida
2
160
これからAgentCoreを触る方へトレンドはGatewayです
har1101
6
450
Spring Security 実践 ─ GraphQL APIで実務に役立つ 認証・認可 を学ぶ
wagyu
0
270
Signal Forms: Details & Live Coding @enterJS 2026 in Mannheim
manfredsteyer
PRO
0
210
Oxlintのカスタムルールの現況
syumai
6
1.2k
メソッドのジェネリクスでGoの夢は広がるか? / Kyoto.go #65
utgwkk
3
1k
Datadog × OpenTelemetry 入門と実践のあいだ
kn_to_maxpno
1
180
スマートグラスで並列バイブコーディング
hyshu
0
270
TAKTでAI駆動開発の品質を設計する
j5ik2o
7
1.6k
キャリア迷子上等 ─ "ない道"は自分で作ればいい
16bitidol
3
2.7k
PHPで使える日時の表現と、その知り方 #frontend_phpcon_do
o0h
PRO
0
280
Contextとはなにか
chiroruxx
1
390
Featured
See All Featured
Accessibility Awareness
sabderemane
1
150
職位にかかわらず全員がリーダーシップを発揮するチーム作り / Building a team where everyone can demonstrate leadership regardless of position
madoxten
62
55k
Leveraging LLMs for student feedback in introductory data science courses - posit::conf(2025)
minecr
1
310
The Limits of Empathy - UXLibs8
cassininazir
1
380
AI Search: Implications for SEO and How to Move Forward - #ShenzhenSEOConference
aleyda
1
1.3k
Digital Projects Gone Horribly Wrong (And the UX Pros Who Still Save the Day) - Dean Schuster
uxyall
1
1.9k
sira's awesome portfolio website redesign presentation
elsirapls
0
290
Efficient Content Optimization with Google Search Console & Apps Script
katarinadahlin
PRO
1
650
Building a Modern Day E-commerce SEO Strategy
aleyda
45
9.1k
How to Get Subject Matter Experts Bought In and Actively Contributing to SEO & PR Initiatives.
livdayseo
0
150
Max Prin - Stacking Signals: How International SEO Comes Together (And Falls Apart)
techseoconnect
PRO
0
190
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
34
2.8k
Transcript
サーバーフレームワークの 仕組みが気になったので 車輪の再発明をしてみた 2022/03/12 NSEEM
自己紹介 HN: マヤミト ID: yt8492 会津大学 学部4年 OtakuProject運営 GitHub: https://github.com/yt8492
趣味: Kotlin, Twitter, ウマ娘 Twitter: yt8492
バックエンドの開発してる人
フレームワークの仕組み、気になりません?
じゃあ作ってみよう!w
今回のテーマ: サーバーフレームワーク自作
やること - TCPのソケット通信をラップしてHTTP通信を実装 - それをもとにフレームワークを実装 - 使用言語はKotlin/Native (苦行) - Cの標準関数のブリッジくらいしか提供されてないので逆に勉強になると思った
- もしこのLTを見ている人が同じことをしたいと思ったら素直に Kotlin/JVMでやることをおすすめしま す
HTTP通信 - HTTPの仕様はRFCで定義されている - 今回はHTTP/1.1でやるのでRFC2616 - TCPのリクエストをどのように解釈して、レスポンスをどのような形式で送ればいいかなどが書かれ ている - リクエストを解釈してレスポンスを返せれば良い
- リクエスト - リクエストライン - ヘッダ - ボディ - レスポンス - ステータスライン - ヘッダ - ボディ
HTTPリクエストを解釈する - TCPのリクエストから以下を解釈できればよい - リクエストライン - ヘッダ - ボディ -
RFCではこのように定義されている - Request = Request-Line *(( general-header | request-header | entity-header ) CRLF) CRLF [ message-body ]
リクエストのリクエストラインを解釈する - RFCではこのように定義されている - Request-Line = Method SP Request-URI SP
HTTP-Version CRLF - メソッド、URI、HTTPバージョンが空白区切りで、最後に CRLF(改行)がある - つまり、ソケット通信で以下のことができればよさそう - CRLFが現れるまで通信を読み込む - 読み込んだバイト列を文字列として扱う - 空白で区切り、それをメソッド、 URI、HTTPバージョンとする
リクエストのリクエストラインを解釈する
リクエストのヘッダを解釈する - ヘッダフィールドのフォーマットは以下のように定義されている - message-header = field-name ":" [ field-value
] field-name = token field-value = *( field-content | LWS ) field-content = <field-value を構成し、*TEXT あるいはtoken, separators, quoted-string を連結したものから成る OCTET> - 名前と値がコロン区切りになっていて、値は前後に 0個以上の空白を含む場合がある - リクエストのヘッダは 0個以上のヘッダフィールドが CRLF区切りになっていて、 CRLFのみの行がヘッ ダの終わりになる
リクエストのヘッダを解釈する - ソケット通信で以下のことができればよさそう - CRLFが現れるまで読み込む - 読み込んだ結果が空であればヘッダの終わり、そうでなければコロンで区切ってそれを名前と値と する - 終わりでない場合は繰り返す
リクエストのボディを解釈する - ボディは以下のように定義されている - message-body = entity-body | <Transfer-Encoding にてエンコードされた
entity-body> - ヘッダに Content-Length や Transfer-Encoding 各ヘッダフィールドを含むとボディが存在し、 な ければボディが空 - Content-Lengthが指定されている場合はそのバイト数だけボディをよみこむ
リクエストのボディを解釈する - 簡単のためTransfer-Encodingは今回考慮しないことに🙏
レスポンスをHTTPの形式にする - 以下の情報をTCPのレスポンスとして返せればよい - ステータスライン - ヘッダ - ボディ -
RFCではこのように定義されている - Response = Status-Line *(( general-header | response-header | entity-header ) CRLF) CRLF [ message-body ]
ステータスラインをTCPのレスポンスに書き込む - RFCではこのように定義されている - Status-Line = HTTP-Version SP Status-Code SP
Reason-Phrase CRLF - つまり、ソケット通信で以下のことができるとよさそう - HTTPバージョンと区切りの空白を書き込む - ステータスコードと区切りの空白を書き込む - 説明句と終端のCRLFを書き込む
ヘッダをTCPのレスポンスに書き込む - 基本的にはリクエストと同じ - ヘッダフィールドの名前と値がコロン区切りになっていて、 CRLFで終わる - CRLFのみの行がヘッダの終わり
ボディをTCPのレスポンスに書き込む - 今回はTransfer-Encodingを考慮しないので単純にボディとして渡されたバイト列 をそのまま書き込む
ここまでがRFCに沿った実装
ここからフレームワークとしての便利実装
フレームワークなら便利であってほしい - HTTPを最低限実装しただけではバックエンド開発に使うには厳しい - Nodeのhttpモジュールとかだけでやろうとするとしんどい - フレームワークなら次のような機能があってほしい - クエリパラメータ -
パスパラメータ - ルーティング
クエリパラメータの取得 - 今回は以下のようになっているという前提で扱う - URIを?で区切った後ろの部分 - 名前=値という形でフィールドが構成され、それが &で連結されている - 名前と値はURLエンコードされる
- 以下のように実装する - URIを?で区切った後ろの部分を取得する - 空でなければさらに &で区切る - 更に=で区切り、それぞれを URLデコードする
ルーティング - 今回はユーザーが以下のように使えるように実装する - get("/hoge") { … }, post("/fuga") {
… } のように、メソッドごとに関数が用意されていて、それ に パスを指定し、ラムダ関数の中で実際にリクエストを受け取ったときの処理を書く - 次のように実装する - ユーザーが get("/hoge") { … } のように関数を呼び出すとハンドラが追加される - ソケットから受け取った TCPのリクエストをHTTPのリクエストとして解釈する - 受け取ったリクエストの URIをもとにどのハンドラで処理するべきか評価し、最も評価度が高いハン ドラに実際に処理をさせる - 処理の結果ユーザーが生成したレスポンスのインスタンスを実際に HTTPのレスポンスとしてTCP のソケットに書き込む
ハンドラの実装 - ハンドラ自体はパスとHTTPメソッドと処理をする関数を持つだけ - ユーザーがHTTPのリクエストに対応した関数を呼び出すとハンドラのリストに追加 されていく
リクエストをハンドラにマッチさせる - 同じリクエストでも複数のハンドラにマッチする可能性がある - /hoge/fuga は /hoge/fuga, /hoge/:param, /hoge/* にマッチする可能性がある
- マッチ度が高いのは /hoge/fuga > /hoge/:param > /hoge/* - これを実際にリクエストが来るたびに行う - ハンドラのパスを/で区切り、それぞれが定数、パスパラメータ、ワイルドカードかど うかによってそのハンドラがマッチした場合の評価度を計算する - パスパラメータを持つ場合は実際にそれを取り出す - ソースコードは結構長くなったのでGitHubまで見に来て
使う側はこんな感じで使える
実際のソースコードはこちら - yt8492/NativeServer https://github.com/yt8492/NativeServer
まとめ - ソケット通信からサーバーフレームワークの実装できた - RFCを読みながら実装するとかなり勉強になる - 自分の知らなかった仕様に出会える - 実際に動くと感動
みんなも車輪の再発明しよう! 楽しいよ!