URL短縮サービス作りました

土曜日, 1月 29th, 2011 by

以前作成していたURL短縮サービスを、大幅改造しました。改良したのは以下の3点です。

  • 独自ドメインの設定
    ドメインが[APPLICATION_NAME].appspot.comでは短縮後のURLが長すぎるので、独自ドメインを設定しました。
  • 例外処理の追加
    正しいURLが入力されていない場合にサーバの投げる例外ではなく、適切なメッセージを表示するようにしました。
  • デザインの適用
    簡単なデザインをつけました。前回と比べればはるかに使いやすくなったはずです。

スクリーンショット

こんな感じになりました。スクリーンショットをクリックすると、サービスのURLに移動します。

GAE/Pythonで作るメリット

GAEで運用すれば、サーバのメンテナンスをしなくて良い。個人で提供するサービスで、正直、サーバの面倒までみている暇はありません。またPythonを使うと、メンテナンス性の高い短いソースコードでサービスを開発できます。大規模プロジェクトであれば、きっちり設計して、Javaなどのコンパイル言語をつかったほうが高速で安定したサービスを開発できるとは思いますが、個人でサービスを作成するなら、開発効率の高いPythonが楽だとおもいます。

ソースコード

いつものお約束。ソースコード全文公開です。今回は、メインのpyファイルのほかに、yamlファイルとCSSファイルも掲載します。メインのプログラムは、デザイン部分やらGoogleAnalyticsのロギングコードまで含めて90行を切っています。短いです。

main.py

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
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
#!/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

class MyHandler(webapp.RequestHandler):
  def write(self, str):
    self.response.out.write(str)

class MainHandler(MyHandler):
  def get(self, pageStr):
    if pageStr == '' or pageStr[0] == '_':
      printHeader(self)
      if pageStr == "_urlerror":
        self.write(u"""<div class="err">正しいURLを入力してください。</div>""")
      self.write(u"""
      <form method="post" action="/"><input type="hidden" name="phpMyAdmin" value="cfc2644bd9c947213a0141747c2608b0" />
        <input type="text" name="url"/>
        <input type="submit" value="短縮">
      </form>"""
)
      printFooter(self)
    else:
      url = URL.all().filter("num = ", int(pageStr, base = 16))
      for u in url:
        self.redirect(u.url)
  def post(self, dummy):
    try:
      url = URL(url = self.request.get('url'))
      num = getNextNum()
      url.put()
      self.redirect("/thanks/%x" % num)
    except Exception:
      self.redirect('_urlerror')

def printHeader(self):
  self.response.out.write(u"""
<html>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<head><title>URL短縮君</title>
<link rel="stylesheet" href="/css/style.css" type="text/css"/>
<script type="text/javascript">
  var _gaq = _gaq || [];
  _gaq.push(['_setAccount', 'UA-20245912-3']);
  _gaq.push(['_trackPageview']);
  (function() {
    var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
    ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
    var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
  })();
</script>
</head>
<body><a href="/?phpMyAdmin=cfc2644bd9c947213a0141747c2608b0"><img src="/img/logo.png" border="0"/></a>"""
)
def printFooter(self):
  self.response.out.write(u"""<br><br>Powered By <a href="http://php6.jp/python">python練習帳</a></body></html>""")

class ThanksHandler(MyHandler):
  def get(self, code):
    printHeader(self)
    self.write(u"""<br/>
    <span class="msg">短縮URL:</span> <input type="text" size="20" value="http://a.php6.jp/%(code)s"/>
    """
% {'code':code})
    printFooter(self)
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()

app.yaml
画像ファイル、CSSファイルは静的なファイルとして提供しています。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
application: pyshortener
version
: 1
runtime
: python
api_version
: 1

handlers
:
- url
: /css/(.*\.css)
  static_files
: css/\1
  upload
: css/(.*\.css)

- url
: /img/(.*\.png)
  static_files
: img/\1
  upload
: img/(.*\.png)

- url
: .*
  script
: main.py

style.css

1
2
3
input, .msg, .err{font-size:30px}
.err{color:red}
body{text-align: center;}

まとめ

  • GAE/Pythonを使うと、個人でも、高負荷に耐えうるサービスを提供できる。
  • サーバの面倒をみなくていいので、運用が楽。基本的に無料。
  • ソースコード短い。

Facebook comments:

comments

Leave a Reply


Get Adobe Flash player
single