GAE/PythonでURL短縮サービス作ってみたので、ソースコード丸ごと公開しちゃいます。
作成したサービスはこちらから利用できます。⇒http://pyshortener.appspot.com/
作成にあたってのポイント
実装上するにあたって工夫した点を紹介します。
連番の取得
短縮URLの短縮コードって連番を16進数や64進数などにエンコードしたものですよね。ということで、短縮URLを作成するためには、連番を作る必要があります。DBとしてMySQLを使っていればauto_incrementを指定するだけで連番が設定されます。だけど、GAE/Pythonには連番を自動生成する手法が容易されていません。そこで、最大値を管理するデータモデル(テーブル)を作成し、getNextNum()で取得できるようにしました。トランザクション内で操作しているので、同じ数字が2回発行されることは無いはずです。
短縮URLは出来るだけ短く
短縮URLはルートディレクトリに対して設定しました。/以降に何も記述されていない場合はURL作成フォームを表示しますが、1文字でも記述されていれば短縮URLが設定されているものと判断します。
ソースコード
1時間で作ったので細かい部分まではつめきれてません。まずい部分があれば指摘いただければと思います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | #!/usr/bin/env python # -*- coding: utf-8 -*- from google.appengine.ext import webapp from google.appengine.ext.webapp import util from google.appengine.ext import db import os class MyHandler(webapp.RequestHandler): def write(self, str): self.response.out.write(str) class MainHandler(MyHandler): def get(self, pageStr): if pageStr == '': self.write(u""" <form method="post" action="/"><input type="hidden" name="phpMyAdmin" value="cfc2644bd9c947213a0141747c2608b0" /> <input type="text" name="url"/> <input type="submit" value="短縮" </form> """) else: url = URL.all().filter("num = ", int(pageStr, base = 16)) for u in url: self.redirect(u.url) def post(self, dummy): num = getNextNum() url = URL(url = self.request.get('url'), num = num) url.put() self.redirect("/thanks/%x" % num) class ThanksHandler(MyHandler): def get(self, code): self.write('<input type="text" size="40" value="http://%(appid)s.appspot.com/%(code)s"/><a href="/?phpMyAdmin=cfc2644bd9c947213a0141747c2608b0">戻る</a>' % {'appid':os.environ["APPLICATION_ID"], 'code':code}) def getNextNum(): def procedure(): num = MAXNUM.get_by_key_name('URL') if num is None: num = MAXNUM(key_name = 'URL') num.max_num = num.max_num + 1 num.put() return num.max_num return db.run_in_transaction(procedure) class URL(db.Model): url = db.URLProperty() num = db.IntegerProperty() class MAXNUM(db.Model): max_num = db.IntegerProperty(default = 0) def main(): application = webapp.WSGIApplication([ ('/thanks/(.*)', ThanksHandler), ('/(.*)', MainHandler) ], debug=True) util.run_wsgi_app(application) if __name__ == '__main__': main() |
まとめ
ドメイン
独自ドメインを設定していないため、短縮URLといっておきながら、全く短くなりません。後日、独自ドメインを設定したいと思います。
デザイン
デザイン面に関しては、協力いただける方がいれば、大歓迎です。
例外処理など
明日にでも実装します。