'성장을 겪고 있는 3년째 웹 엔지니어를 위한 파이썬 웹 애플리케이션 자작 입문'을 업데이트했습니다.
책을 업데이트했습니다.
챕터 「「동적으로 생성한 HTML」을 돌려줄 수 있게 된다」를 업데이트했습니다.
계속을 읽고 싶은 분은, 꼭 Book의 「좋아요」인가 「필자 팔로우」를 부탁합니다 ;-)
이하, 책의 내용의 발췌입니다.
'정적 파일 전달' 및 '동적 HTML 생성'
그런데, 지금까지 「적절한 헤더의 생성」( Date
라든지, Content-Type
라든지)을 할 수 있게 되어, 「병렬 처리」도 할 수 있게 되어, HTTPのルールに従ってレスポンスを返す基盤
의 부분은 꽤 갖추어져 왔습니다 .
이제 웹 서버(=HTTP 서버)로 최소한의 기능을 갖추게 된다는 단계는 거의 끝입니다.
다음 단계로 "응답 본문으로 무엇을 반환합니까?"에 대해 좀 더 자세히 살펴 보겠습니다.
이미 구현되어 있는 「HTML 파일이나 화상 파일의 내용을 응답 본체로서 그대로 돌려준다」라고 하는 기능을, 일반적으로는 「정적 파일 전달」이라고 부릅니다.
이 기능만 있으면, 예를 들면 IETF에 의한 RFC 웹 페이지 등은 충분히 작성 가능합니다.
내용을 HTML 파일에 써 저장해 두면 좋을 뿐이니까요.
하지만 여러분의 익숙한 홈페이지를 만들려면 여전히 기능이 부족합니다.
예를 들면 마에바시 선생님의 홈페이지 ^[본서를 쓰는 계기를 주어 받은 「웹 서버를 만들면서 배우는 기초로부터의 Web 어플리케이션 개발 입문」의 저자입니다. 자세한 것은 여기 ] 와 같은 비교적 간소한^ ] 홈페이지조차도 아직 만들 수 없습니다.
무엇을 만들 수 없는가 하면, 아래와 같은 소위 「액세스 카운터」의 부분입니다.
アクセスカウンターの数字は、ページを読み込むごとに数字が増えていきます。
この機能を、皆さんの今のWebサーバーで実現するにはどうすればいいでしょうか?
アクセスカウンターの数字が変わるということは、レスポンスボディの内容が変わるということです。
現在のWebサーバーから返却されるレスポンスボディはHTMLファイルの内容そのままですので、レスポンスボディの内容を変えようと思うとHTMLファイルを編集する必要があります。
つまり、この機能を提供しようと思うと、HTTPリクエストが来る度に毎回HTMLファイルを自動で(もしくは手動で)編集して保存するような機能が必要になってしまいます。
これは(実現可能ですが)あまりに非効率そうですし、面倒くさそうです。
そうなってくると、
「レスポンスボディをファイルから取得するのではなく、Pythonの文字列として生成すれば毎回違うレスポンスボディを生成するのは簡単なのでは?」
という発想になるのは自然なことでしょう。
これを 「動的なHTMLの生成」(あるいは 「動的なレスポンスの生成」)と呼びます。
칼럼: "정적"과 "동적"
「静的」という言葉はなかなか厄介です。また、対義語である「動的」という言葉も同様に厄介です。
「静的」とは「変化しないもの」、「動的」は「変化するもの」を意味するわけですが、「何に対して何が静的なのか」「何に対して何が動的なのか」を常に意識する必要があります。
例えば「 静的ファイル
配信」は「 変化しないファイル
の配信」を意味しています。
これは、何に対して何が変化しないファイルなのでしょうか?
HTMLファイルそのものは、常に変化しえます。ファイルをエディタで編集するだけです。
Webサーバーの機能として見た時も、HTMLファイルを編集してしまうとレスポンスボディも変化してしまうでしょう。
「静的ファイル配信」のことを「"いつも"同じレスポンスが返ってくるWebサービス」と表現する方もいらっしゃいますが、このことを考えると正確ではないことが分かります。
HTMLファイルを編集すればレスポンスも変化するのですから。
答えは、「リクエストに対して内容が変化しないファイルの配信」です。
「リクエストに応じて内容を変化させないファイルの配信」と言ったほうが分かりやすいかもしれません。
ですので、ファイルを編集したときは、内容が変化してもよいのです。
私がジュニアエンジニアだったころは、
「でもHTMLファイルを編集したらレスポンスは変わるんでしょ?いつも同じって嘘じゃない?」
と思って混乱していました。
また他にも、Javascriptを説明する際に「Web上で動的なコンテンツを提供するためのプログラミング言語」と説明されることがあります。
この説明における「動的なコンテンツ」というのは、「時間の経過あるいはユーザーの操作に対して、配信済みのHTMLが変化するコンテンツ」のことです^[正確にはJavascriptが変化させるのはDOMであってHTMLではありませんが、そこはご愛嬌。]。
ブラウザに表示させるHTMLは一度レスポンスとしてブラウザへ送ってしまうと、サーバー側のプログラムから変更させることは基本的にはできません。
CSSなどは確かにコンテンツの表示内容を変化(文字の色を赤くしたり)させますが、配信済みのHTMLの内容を変化させているわけではありません。
ただし、HTMLと一緒にプログラムをブラウザに送りつけておけば、ブラウザがそのプログラムを後から実行することで配信済みのHTMLを変更させることができます。
それがJavascriptなのです。
単に「動的なコンテンツ」を「Webページを変化させる」とだけ理解してしまうと、
「文字の色を変化させるCSSも動的コンテンツを提供しているのでは?」
「HTMLのformタグもボタンを押すかどうかでページの挙動が変わるわけだから、動的なのでは?」
などと混乱してしまいます。
(私は混乱していました。)
このように「静的」「動的」という言葉はよく出てくるわりに理解が難しいので、何に対して何が変化する/しないのか、常に注意しておきましょう。
현재 시간을 표시하는 페이지 만들기
少し回りくどい説明をしてしまいましたが、やりたいことはソースコードを見てもらったほうが早いかもしれません。
実際に「動的なHTMLの生成」を行い、リクエストする度に結果が変わるようなページを作成してみましょう。
アクセスカウンターをいきなり実装するには過去のアクセス数を保存しておくデータベースのようなものが必要になり少し面倒ですので、まずは簡単のため /now
というpathにアクセスすると現在時刻を表示するだけのページを作成してみましょう。
(アクセスカウンターの実装はもう少し後で取り組みます。)
소스 코드
現在時刻を表示するページを追加するために、 workerthread.py
を変更したソースコードがこちらです。
study/workerthread.py htps : // 기주 b. 코 m/비겐 1925/인 t 로즈 c 치온-우-b-아 p-카치 온-우 thpy 쵸/bぉb/마이/코데 s/챠 p r14/ r rth rea d. py
해설
42-59행
response_body: bytes
response_line: str
# pathが/nowのときは、現在時刻を表示するHTMLを生成する
if path == "/now":
html = f"""\
<html>
<body>
<h1>Now: {datetime.now()}</h1>
</body>
</html>
"""
response_body = textwrap.dedent(html).encode()
# レスポンスラインを生成
response_line = "HTTP/1.1 200 OK\r\n"
# pathがそれ以外のときは、静的ファイルからレスポンスを生成する
else:
# ...
추가한 것은 이 부분입니다.
하는 일은
"path가 /now
그렇다면 파이썬에서 현재 시간을 표시하는 HTML을 생성하고 응답 본문으로 만듭니다"
라는 것입니다.
소스 코드에 대해 몇 가지 보충해 둡니다.
response_body: bytes
response_line: str
response_body
이나 response_line
를 대입하는 개소가 복수로 나누어져 버리고 있으므로, 사전에 형 주석을 해 두기로 했습니다.
변수의 형태 주석은, 에디터등에 「이 변수는 이 형태의 값을 대입하는 것을 상정하고 있어요」라고 힌트를 전하는 의미가 있습니다.
이와 같이 기재해 두면, 잘못해 「저쪽에서는 str
를 대입, 이쪽에서는 bytes
를 대입」등으로서 버렸을 때에 에디터가 사전에 경고해 줍니다.
html = f"""\
<html>
<body>
<h1>Now: {datetime.now()}</h1>
</body>
</html>
"""
response_body = textwrap.dedent(html).encode()
ヒアドキュメント
+ dedent()
를 사용하고 있습니다.
단순히 보통 html을 쓰고 싶을 뿐입니다만, 들여쓰기나 개행이 python에서는 의미를 가지고 버리므로, 궁리하고 있습니다.
그리 어렵지 않기 때문에, 「python 히어 문서」「python dedent」등으로 조사해 보세요.
움직여 보자
그럼 조속히 움직이자.
평소와 같이 서버를 시작한 후 Chrome에서 http://localhost:8080/now
로 이동해보십시오.
질소이지만 위와 같은 페이지가 표시되었습니까?
메시지가 표시되면 페이지를 여러 번 다시 로드해 보세요.
매번 표시되는 내용이 바뀌고 있습니까?
이것으로 동적 HTML 생성의 완료입니다.
쉬웠어요.
다시 되돌아 보면 이번에 한 일의 중요한 포인트는
"서버 시작 후 소스 코드도 HTML 파일도 전혀 편집하지 않았는데 매번 다른 결과가 브라우저에 표시된다"
라는 것입니다.
단순히 파일의 내용을 그대로 응답 바디로 출력하고 있는 것만으로는 실현할 수 없었던 기능입니다.
HTTP 요청의 내용을 표시하는 페이지 만들기
모처럼이므로, 또 하나 정도 동적인 HTML의 페이지를 만들어 봅시다.
다음은 보내진 HTTP 요청의 내용을 그대로 HTML로 표시하는 /show_request 라는 페이지를 추가해 보겠습니다.
계속은 Book에서! 챕터 「「동적으로 생성한 HTML」을 돌려줄 수 있게 된다」
그런데, 지금까지 「적절한 헤더의 생성」(
Date
라든지, Content-Type
라든지)을 할 수 있게 되어, 「병렬 처리」도 할 수 있게 되어, HTTPのルールに従ってレスポンスを返す基盤
의 부분은 꽤 갖추어져 왔습니다 .이제 웹 서버(=HTTP 서버)로 최소한의 기능을 갖추게 된다는 단계는 거의 끝입니다.
다음 단계로 "응답 본문으로 무엇을 반환합니까?"에 대해 좀 더 자세히 살펴 보겠습니다.
이미 구현되어 있는 「HTML 파일이나 화상 파일의 내용을 응답 본체로서 그대로 돌려준다」라고 하는 기능을, 일반적으로는 「정적 파일 전달」이라고 부릅니다.
이 기능만 있으면, 예를 들면 IETF에 의한 RFC 웹 페이지 등은 충분히 작성 가능합니다.
내용을 HTML 파일에 써 저장해 두면 좋을 뿐이니까요.
하지만 여러분의 익숙한 홈페이지를 만들려면 여전히 기능이 부족합니다.
예를 들면 마에바시 선생님의 홈페이지 ^[본서를 쓰는 계기를 주어 받은 「웹 서버를 만들면서 배우는 기초로부터의 Web 어플리케이션 개발 입문」의 저자입니다. 자세한 것은 여기 ] 와 같은 비교적 간소한^ ] 홈페이지조차도 아직 만들 수 없습니다.
무엇을 만들 수 없는가 하면, 아래와 같은 소위 「액세스 카운터」의 부분입니다.
アクセスカウンターの数字は、ページを読み込むごとに数字が増えていきます。
この機能を、皆さんの今のWebサーバーで実現するにはどうすればいいでしょうか?
アクセスカウンターの数字が変わるということは、レスポンスボディの内容が変わるということです。
現在のWebサーバーから返却されるレスポンスボディはHTMLファイルの内容そのままですので、レスポンスボディの内容を変えようと思うとHTMLファイルを編集する必要があります。
つまり、この機能を提供しようと思うと、HTTPリクエストが来る度に毎回HTMLファイルを自動で(もしくは手動で)編集して保存するような機能が必要になってしまいます。
これは(実現可能ですが)あまりに非効率そうですし、面倒くさそうです。
そうなってくると、
「レスポンスボディをファイルから取得するのではなく、Pythonの文字列として生成すれば毎回違うレスポンスボディを生成するのは簡単なのでは?」
という発想になるのは自然なことでしょう。
これを 「動的なHTMLの生成」(あるいは 「動的なレスポンスの生成」)と呼びます。
칼럼: "정적"과 "동적"
「静的」という言葉はなかなか厄介です。また、対義語である「動的」という言葉も同様に厄介です。
「静的」とは「変化しないもの」、「動的」は「変化するもの」を意味するわけですが、「何に対して何が静的なのか」「何に対して何が動的なのか」を常に意識する必要があります。
例えば「 静的ファイル
配信」は「 変化しないファイル
の配信」を意味しています。
これは、何に対して何が変化しないファイルなのでしょうか?
HTMLファイルそのものは、常に変化しえます。ファイルをエディタで編集するだけです。
Webサーバーの機能として見た時も、HTMLファイルを編集してしまうとレスポンスボディも変化してしまうでしょう。
「静的ファイル配信」のことを「"いつも"同じレスポンスが返ってくるWebサービス」と表現する方もいらっしゃいますが、このことを考えると正確ではないことが分かります。
HTMLファイルを編集すればレスポンスも変化するのですから。
答えは、「リクエストに対して内容が変化しないファイルの配信」です。
「リクエストに応じて内容を変化させないファイルの配信」と言ったほうが分かりやすいかもしれません。
ですので、ファイルを編集したときは、内容が変化してもよいのです。
私がジュニアエンジニアだったころは、
「でもHTMLファイルを編集したらレスポンスは変わるんでしょ?いつも同じって嘘じゃない?」
と思って混乱していました。
また他にも、Javascriptを説明する際に「Web上で動的なコンテンツを提供するためのプログラミング言語」と説明されることがあります。
この説明における「動的なコンテンツ」というのは、「時間の経過あるいはユーザーの操作に対して、配信済みのHTMLが変化するコンテンツ」のことです^[正確にはJavascriptが変化させるのはDOMであってHTMLではありませんが、そこはご愛嬌。]。
ブラウザに表示させるHTMLは一度レスポンスとしてブラウザへ送ってしまうと、サーバー側のプログラムから変更させることは基本的にはできません。
CSSなどは確かにコンテンツの表示内容を変化(文字の色を赤くしたり)させますが、配信済みのHTMLの内容を変化させているわけではありません。
ただし、HTMLと一緒にプログラムをブラウザに送りつけておけば、ブラウザがそのプログラムを後から実行することで配信済みのHTMLを変更させることができます。
それがJavascriptなのです。
単に「動的なコンテンツ」を「Webページを変化させる」とだけ理解してしまうと、
「文字の色を変化させるCSSも動的コンテンツを提供しているのでは?」
「HTMLのformタグもボタンを押すかどうかでページの挙動が変わるわけだから、動的なのでは?」
などと混乱してしまいます。
(私は混乱していました。)
このように「静的」「動的」という言葉はよく出てくるわりに理解が難しいので、何に対して何が変化する/しないのか、常に注意しておきましょう。
현재 시간을 표시하는 페이지 만들기
少し回りくどい説明をしてしまいましたが、やりたいことはソースコードを見てもらったほうが早いかもしれません。
実際に「動的なHTMLの生成」を行い、リクエストする度に結果が変わるようなページを作成してみましょう。
アクセスカウンターをいきなり実装するには過去のアクセス数を保存しておくデータベースのようなものが必要になり少し面倒ですので、まずは簡単のため /now
というpathにアクセスすると現在時刻を表示するだけのページを作成してみましょう。
(アクセスカウンターの実装はもう少し後で取り組みます。)
소스 코드
現在時刻を表示するページを追加するために、 workerthread.py
を変更したソースコードがこちらです。
해설
42-59행
response_body: bytes
response_line: str
# pathが/nowのときは、現在時刻を表示するHTMLを生成する
if path == "/now":
html = f"""\
<html>
<body>
<h1>Now: {datetime.now()}</h1>
</body>
</html>
"""
response_body = textwrap.dedent(html).encode()
# レスポンスラインを生成
response_line = "HTTP/1.1 200 OK\r\n"
# pathがそれ以外のときは、静的ファイルからレスポンスを生成する
else:
# ...
추가한 것은 이 부분입니다.
하는 일은
"path가
/now
그렇다면 파이썬에서 현재 시간을 표시하는 HTML을 생성하고 응답 본문으로 만듭니다"라는 것입니다.
소스 코드에 대해 몇 가지 보충해 둡니다.
response_body: bytes
response_line: str
response_body
이나 response_line
를 대입하는 개소가 복수로 나누어져 버리고 있으므로, 사전에 형 주석을 해 두기로 했습니다.변수의 형태 주석은, 에디터등에 「이 변수는 이 형태의 값을 대입하는 것을 상정하고 있어요」라고 힌트를 전하는 의미가 있습니다.
이와 같이 기재해 두면, 잘못해 「저쪽에서는
str
를 대입, 이쪽에서는 bytes
를 대입」등으로서 버렸을 때에 에디터가 사전에 경고해 줍니다. html = f"""\
<html>
<body>
<h1>Now: {datetime.now()}</h1>
</body>
</html>
"""
response_body = textwrap.dedent(html).encode()
ヒアドキュメント
+ dedent()
를 사용하고 있습니다.단순히 보통 html을 쓰고 싶을 뿐입니다만, 들여쓰기나 개행이 python에서는 의미를 가지고 버리므로, 궁리하고 있습니다.
그리 어렵지 않기 때문에, 「python 히어 문서」「python dedent」등으로 조사해 보세요.
움직여 보자
그럼 조속히 움직이자.
평소와 같이 서버를 시작한 후 Chrome에서
http://localhost:8080/now
로 이동해보십시오.질소이지만 위와 같은 페이지가 표시되었습니까? 메시지가 표시되면 페이지를 여러 번 다시 로드해 보세요. 매번 표시되는 내용이 바뀌고 있습니까? 이것으로 동적 HTML 생성의 완료입니다. 쉬웠어요. 다시 되돌아 보면 이번에 한 일의 중요한 포인트는 "서버 시작 후 소스 코드도 HTML 파일도 전혀 편집하지 않았는데 매번 다른 결과가 브라우저에 표시된다" 라는 것입니다. 단순히 파일의 내용을 그대로 응답 바디로 출력하고 있는 것만으로는 실현할 수 없었던 기능입니다. HTTP 요청의 내용을 표시하는 페이지 만들기 모처럼이므로, 또 하나 정도 동적인 HTML의 페이지를 만들어 봅시다. 다음은 보내진 HTTP 요청의 내용을 그대로 HTML로 표시하는 /show_request 라는 페이지를 추가해 보겠습니다. 계속은 Book에서! 챕터 「「동적으로 생성한 HTML」을 돌려줄 수 있게 된다」