webapp2にてhttpのheadメソッドに対応してみた。

2013年05月07日

最近、アクセスログを見ていると、HEADメソッドのリクエストがあることに気が付きました。ほぼロボット検索の様なのです。

どうやら、リンク先がの有無を調べる時などに利用されているようです。

実は、今回調べるまでHAEDメソッドの存在すら知らなかったのですが、GETメソッドと同じだがbodyを返さない仕様らしく、データの送受信量を減らすことが目的のようです。

しかも、HTTP/1.1では、GETとHEADは実装しなければいけない。という記載も見受けられます。

ちなみに、僕の管理サイトでは、googlebotからのHEADメソッドは、2013年5月2日から入ってくるようになっていました。

そんな感じで、googleさんからのリクエストにはちゃんと答えるべきだろう。と思って、実装方法を考えてみました。

以下は、Google App Engine for Pythonで標準となっているwebapp2での実装になります。

基本的には、GETと同じ内容で、生成されたresponseからbodyを削除するというのが基本的な考え方でコーディングしてみました。

 結果、こんな感じのコードになりました。

class HomeHandler(webapp2.RequestHandler):
    def get(self):
        self.response.out.write(u'レスポンスコンテンツ')

    def head(self):
        self.get()
        # bodyクリア前のレングスを取得
        content_length = self.response.headers['Content-Length']
        self.response.out.clear()
        # bodyクリア前のレングスをセット
        self.response.headers['Content-Length'] = content_length
        # 動作確認用にログを出力
        logging.info(self.response)

def get(self)は、通常通りコンテンツを作成します。

def head(self)を追加し、def get(self)を呼び出しています。

 getで作成したresponseのheadersにセットされたContent-Lengthを保存してから、self.response.out.clear()でbodyをクリアしています。

その後保存したContent-Lengthをセットし直しています。

再度セットしなおさないと、bodyをクリアした際にContent-Lengthがクリアされてしまいました。

 

ちなみに、コードのテストはheadメソッドを生成するのが面倒だったので、def getにhead用のロジックを入れて確認しました。

本当は、UnitTestを書いてテストするべきなのでしょうが、ちょっとサボりました。。

localで確認する場合には、ターミナルでtelnetを使ってリクエストを出すと簡単かもしれません。その方法は、こちらのサイトを参考にさせて頂きました。

HTTP クライアントを作ってみよう(3)

 

ロボット検索が意図したレスポンスになっているかは、良く分かりません。。。

  

----2013/5/10 追記-----

ここまで来たら、当然共通ロジックにした方がいいですよね。というか、するべきですよね。

webapp2は、get,post,headのそれぞれのメソッドを個別にコーディングしなければ行けないのですが、postも特別コーディング指定なければ、getと同じ動きをしてくれる方が便利ですよね。僕が今まで使っていたJavaのフレームワークとかも意識せずにその動きをしていたので、共通ロジックに入れてみました。

 

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import webapp2
import logging


class ComRequestHandler(webapp2.RequestHandler):
    def get(self, *args, **kwargs):
        self.abort(405)

    def post(self, *args, **kwargs):
        self.get(*args, **kwargs)

    def head(self, *args, **kwargs):
        self.get(*args, **kwargs)
        logging.info(self.response.headers)
        content_length = self.response.headers['Content-Length']
        self.response.out.clear()
        self.response.headers['Content-Length'] = content_length
        logging.info(self.response)

 

こんな感じになりました。loggingはデバッグ用です。getで405を返すようにしているのは、当クラス内でgetを定義した方が分かりやすいかと思ったのと、継承先でgetを実装していない場合に、405を返すべきかと思ったのでこんな感じになりました。

もっと、いい方法はあると思いますけど、これからもう少し勉強してみます。

 



PAGE TOP