□未翻訳
□翻訳中
□翻訳完了(細田謙二)
■レビュー(中垣健志)

URLリライト

web2pyでは、コントローラのアクションを呼び出す前に、入力されるリクエストのURLパスを書き換えることができます(URLマッピング)。逆に、URL関数によって生成されたURLパスも書き換えることができます(リバースURLマッピング)。これを行う理由の1つは、古い仕様のURLを扱うためです。もう1つはパスを単純化し、短くするためです。
web2py has the ability to rewrite the URL path of incoming requests prior to calling the controller action (URL mapping), and conversely, web2py can rewrite the URL path generated by the URL function (reverse URL mapping). One reason to do this is for handling legacy URLs, another is to simplify paths and make them shorter.

web2pyは2つの異なるURLリライトシステムを内蔵しています。1つは、大抵のユースケースのための簡便なパラメータベースのシステムです。もう1つは、より複雑なケースのための、柔軟なパターンベースのシステムです。URLリライトルールを指定するには、"web2py"フォルダにてroutes.pyという名の新規ファイルを作成します(routes.pyの中身は、次の節で説明するように、どちらのリライトシステムを選択したかに依存します)。
web2py includes two distinct URL rewrite systems: an easy-to-use parameter-based system for most use cases, and a flexible pattern-based system for more complex cases. To specify the URL rewrite rules, create a new file in the "web2py" folder called routes.py (the contents ofroutes.py will depend on which of the two rewrite systems you choose, as described in the next two sections).

パラメータベースのシステム
Parameter-Based System

myappというアプリケーションを書いていて、それをデフォルトにし、アプリケーションの名前をユーザに見せるURLの一部に含めないようにしたいとします。デフォルトのコントローラはまだdefaultなので、その名前もユーザが見るURLから取り除きたいとします。routes.pyに書くものは次のようになります:
Suppose you've written an application called myapp and wish to make it the default, so that the application name is no longer part of the URL as seen by the user. Your default controller is still default, and you want to remove its name from user-visible URLs as well. Here's what you put in routes.py:

1.
2.
3.
routers = dict( 
BASE = dict(default_application='myapp'),
)

それだけです。このルータは十分賢く、次のようなURLを正しく扱う方法を知っています:
That's it. The router is smart enough to know how to do the right thing with URLs such as:

http://domain.com/myapp/default/myapp

または
or

http://domain.com/myapp/myapp/index

ここで、通常の短縮化では曖昧さがあります。myappとmyapp2という2つのアプリケーションがあるときも同様の効果が得られ、追加したmyapp2のデフォルトコントローラは、安全である場合(ほぼすべての場合)は常に、URLから取り除かれます。
where normal shortening would be ambiguous. If you have two applications, myapp andmyapp2, you'll get the same effect, and additionally myapp2's default controller will be stripped from the URL whenever it's safe (which is mostly all the time).

別のケースを考えます:次のようなURLに基づいた言語をサポートしたいとします:
Here is another case: suppose you want to support URL-based languages, where your URLs look like this:

http://myapp/en/some/path

または(リライトされて)
or (rewritten)

http://en/some/path

その方法は次のようになります:
Here's how:

1.
2.
3.
4.
routers = dict( 
BASE = dict(default_application='myapp'),
myapp = dict(languages=['en', 'it', 'jp'], default_language='en'),
)

すると、次のような入力URLは:
Now an incoming URL like this:

http:/domain.com/it/some/path

/myapp/some/pathに転送され、request.uri_languageが'it'に設定され、翻訳を実施することができます。また、言語固有の静的ファイルも持つことができます。
will be routed to /myapp/some/path, and request.uri_language will be set to 'it', so you can force the translation. You can also have language-specific static files.

http://domain.com/it/static/filename

これは次のものにマッピングされます:
will be mapped to:
1.
applications/myapp/static/it/filename
ただし、これはファイルが存在する場合です。もし存在しなければ、次のようなURLは:
if that file exists. If it doesn't, then URLs like:

http://domain.com/it/static/base.css

さらに次のものにマッピングされます:
will still map to:
1.
applications/myapp/static/base.css
(static/it/base.cssというファイルがないからです)。
(because there is no static/it/base.css).

このようにして、画像なども含め、言語固有の静的ファイルを持つことができるようになります。ドメインのマッピングも同様にサポートされています:
So you can now have language-specific static files, including images, if you need to. Domain mapping is supported as well:
1.
2.
3.
4.
5.
6.
7.
8.
routers = dict( 
BASE = dict(
domains = {
'domain1.com' : 'app1',
'domain2.com' : 'app2',
}
),
)
これは想定通りに機能します。
does what you'd expect.
1.
2.
3.
4.
5.
6.
7.
8.
routers = dict( 
BASE = dict(
domains = {
'domain.com:80' : 'app/insecure',
'domain.com:443' : 'app/secure',
}
),
)
これは、http://domain.comへのアクセスを、insecureというコントローラにマッピングする一方、HTTPSのアクセスをsecureコントローラに流します。同様に、異なるポートを異なるアプリにマッピングすることも、明らかな方法で可能です。
maps http://domain.com accesses to the controller named insecure, while HTTPS accesses go to the secure controller. Alternatively, you can map different ports to different apps, in the obvious way.

より詳しい情報については、router.example.pyファイルを参考にしてください。このファイルは、標準のweb2py配布の基底フォルダにおいて提供されています。
For further information, please consult the file router.example.py provided in the base folder of the standard web2py distribution.

注:このパラメータベースのシステムは、web2pyのバージョン1.92.1で初めて登場しました。
Note: This parameter-based system first appeared in web2py version 1.92.1.


パターンベースのシステム
Pattern-Based System

今述べたパラメータベースのシステムは、大抵のユースケースに対して満足できるものですが、もう1つのパターンベースのシステムは、より複雑なケースのためにさらなる柔軟性があります。パターンベースのシステムを使うには、ルーティングパラメータの辞書としてルータを定義する代わりに、routes_inとroutes_outという2つのリスト(またはタプル)を定義します。各タプルは2つの要素を格納します:置換されるパターンとそこに置換する文字列です。たとえば:
Although the parameter-based system just described should be sufficient for most use cases, the alternative pattern-based system provides some additional flexibility for more complex cases. To use the pattern-based system, instead of defining routers as dictionaries of routing parameters, you define two lists (or tuples) of 2-tuples, routes_in and routes_out. Each tuple contains two elements: the pattern to be replaced and the string that replaces it. For example:

1.
2.
3.
4.
5.
6.
routes_in = (
(
'/testme', '/examples/default/index'),
)
routes_out = (
(
'/examples/default/index', '/testme'),
)

これらのルーティングによって次のURLは:
With these routes, the URL:

http://127.0.0.1:8000/testme

以下のものにマッピングされます:
is mapped into:

http://127.0.0.1:8000/examples/default/index

訪問者にとって、すべてのページのURLは/testmeのように提示されます。
To the visitor, all links to the page URL looks like /testme.

パータンはPythonの正規表現と同じ構文を持っています。たとえば:
The patterns have the same syntax as Python regular expressions. For example:

1.
('.*\.php', '/init/default/index'),

これは、".php"で終わるすべてのURLがインデックスページにマッピングされます。
maps all URLs ending in ".php" to the index page.

1つのアプリケーションしか公開するつもりがない場合、アプリケーションのプレフィックスをURLから取り除きたい場合があります。これは次のようにして実現できます:
Sometimes you want to get rid of the application prefix from the URLs because you plan to expose only one application. This can be achieved with:

1.
2.
3.
4.
5.
6.
routes_in = (
(
'/(?P<any>.*)', '/init/\g<any>'),
)
routes_out = (
(
'/init/(?P<any>.*)', '/\g<any>'),
)

上記の正規表現と混ぜることができるもう1つの別の構文があります。これは、(?P<name>\w+) や \g<name>の代わりに$nameを用います。例:
There is also an alternative syntax that can be mixed with the regular expression notation above. It consists of using $name instead of (?P<name>\w+) or \g<name>. For example:

1.
2.
3.
4.
5.
6.
7.
routes_in = (
(
'/$c/$f', '/init/$c/$f'),
)

routes_out = (
(
'/init/$c/$f', '/$c/$f'),
)

これは、"/example"アプリケーションのプレフィックスをすべてのURLにおいて取り除きます。
would also eliminate the "/example" application prefix in all URLs.

$name表記を使用して、routes_inからroutes_outへ自動的にマッピングすることが可能になります。ただしこの場合、正規表現を使用することはできません。たとえば次のようになります:
Using the $name notation, you can automatically map routes_in to routes_out, provided you don't use any regular expressions. For example:

1.
2.
3.
4.
5.
routes_in = (
(
'/$c/$f', '/init/$c/$f'),
)

routes_out = [(x, y) for (y, x) in routes_in]

ここで複数のルーティングがある場合、最初にマッチしたURLが実行されます。もしマッチするパタンがない場合、パスはそのままになります。
If there are multiple routes, the first to match the URL is executed. If no pattern matches, the path is left unchanged.

$anythingを用いると、行の最後までのすべて(.*)にマッチさせることができます。
You can use $anything to match anything (.*) until the end of the line.

ここでは、faviconとrobotsリクエストを処理するための最小限の"routes.py"を示します:
Here is a minimal "routes.py" for handling favicon and robots requests:

1.
2.
3.
4.
5.
routes_in = (
(
'/favicon.ico', '/examples/static/favicon.ico'),
(
'/robots.txt', '/examples/static/robots.txt'),
)
routes_out = ()


さらに、複雑な例を示します。"myapp"という単一のアプリを、不必要なプレフィックスなしに公開しますが、同時に、adminとappadminとstaticも公開するという例です。
Here is a more complex example that exposes a single app "myapp" without unnecessary prefixes but also exposes adminappadmin and static:

1.
2.
3.
4.
5.
6.
7.
8.
routes_in = (
(
'/admin/$anything', '/admin/$anything'),
(
'/static/$anything', '/myapp/static/$anything'),
(
'/appadmin/$anything', '/myapp/appadmin/$anything'),
(
'/favicon.ico', '/myapp/static/favicon.ico'),
(
'/robots.txt', '/myapp/static/robots.txt'),
)
routes_out = [(x, y) for (y, x) in routes_in[:-2]]

ルーティングの一般的な構文は、これまで見てきた簡単な例よりも複雑です:ここではより一般的で代表的な例を示します:
The general syntax for routes is more complex than the simple examples we have seen so far. Here is a more general and representative example:

1.
2.
3.
4.
routes_in = (
(
'140\.191\.\d+\.\d+:https://www.web2py.com:POST /(?P<any>.*)\.php',
'/test/default/index?vars=\g<any>'),
)

これは、httpsのPOSTリクエストを、次の正規表現にマッチしたリモートIPから、www.web2py.comというホストにマッピングします。
It maps https POST requests to host www.web2py.com from a remote IP matching the regular expression

1.
'140\.191\.\d+\.\d+'

そして、次の正規表現にマッチしたページを
requesting a page matching the regular expression

1.
'/(?P<any>.*)\.php'

次のものへとリクエストします。
into

1.
'/test/default/index?vars=\g<any>'

ここで、 \g<any>は、マッチした正規表現によって置換されます。
where \g<any> is replaced by the matching regular expression.

全般的な構文は以下のとおりです:
The general syntax is

1.
'[remote address]:[protocol]://[host]:[method] [path]'

表現全体は正規表現としてマッチするので、"."は常にエスケープされ、マッチした部分表現はすべて、Pythonの正規表現の構文に従って(?P<...>...)を用いて捉えることができます。
The entire expression is matched as a regular expression, so "." should always be escaped and any matching subexpression can be captured using (?P<...>...) according to Python regex syntax.

これにより、クライアントのIPアドレスやドメインに基づいて、また、リクエストのタイプやメソッド、パスに基づいて、リクエストを再ルーティングすることが可能になります。また、異なるバーチャルホストを異なるアプリケーションにマッピングすることも可能です。マッチした部分表現はターゲットのURLを構築するために用いることができ、結果的に、GET変数に渡すことができます。
This allows to reroute requests based on the client IP address or domain, based on the type of the request, on the method, and the path. It also allows to map different virtual hosts into different applications. Any matched subexpression can be used to built the target URL and, eventually, passed as a GET variable.

Apacheやlighttpdなどのすべての主要なWebサーバーは、URLをリライトする機能を持っています。本番環境では、それらはroutes.pyに代わる選択肢になります。いずれにせよ、アプリの内部URLをハードコードせず、URL関数でそれらを生成することを強く推奨します。これにより、必要であればルーツを変更することで、あなたのアプリケーションはよりポータブルなものになります。
All major web servers, such as Apache and lighttpd, also have the ability to rewrite URLs. In a production environment that may be an option instead of routes.py. Whatever you decide to do we strongly suggest that you do not hardcode internal URLs in your app and use the URL function to generate them. This will make your application more portable in case routes should change.

アプリケーション固有のURLリライト
Application-Specific URL Rewrite


パターンベースのシステムを使用したとき、アプリケーションは独自のルーティングを、アプリケーションの基底フォルダに置かれたアプリケーション固有のroutes.pyにて、設定することができます。これはroutes_appを、入力URLから選択するアプリケーションの名前を決める基底のroutes.pyにて設定することで可能になります。このとき、アプリケーション固有のroutes.pyが基底のroutes.pyの代わりに使用されます。
When using the pattern-based system, an application can set its own routes in an application-specific routes.py file located in the applications base folder. This is enabled by configuringroutes_app in the base routes.py to determine from an incoming URL the name of the application to be selected. When this happens, the application-specific routes.py is used in place of the base routes.py.

routes_appのフォーマットはroutes_inと全く同じです。ただし置換パターンが単純にアプリケーションの名前になります。routes_appを入力URLに適用してアプリケーション名にならない場合、または、アプリケーション固有のroutes.pyが見つからない場合、基底のroutes.pyがこれまで通り使用されます。
The format of routes_app is identical to routes_in, except that the replacement pattern is simply the application name. If applying routes_app to the incoming URL does not result in an application name, or the resulting application-specific routes.py is not found, the base routes.py is used as usual.

注: routes_appはweb2pyのバージョン1.83で初めて登場しました。
Note: routes_app first appeared in web2py version 1.83.


デフォルトのアプリケーション、コントローラ、関数
Default Application, Controller, and Function

パターンベースのシステムを使うとき、デフォルトのアプリケーション、コントローラ、関数は、routes.pyで適切な値を設定することで、init、default、indexから違う名前にそれぞれ変更することができます:
When using the pattern-based system, the name of the default application, controller, and function can be changed from initdefault, and index respectively to another name by setting the appropriate value in routes.py:

1.
2.
3.
default_application = "myapp"
default_controller = "admin"
default_function = "start"

注:これらの項目は、web2pyのバージョン1.83で初めて登場しました。
Note: These items first appeared in web2py version 1.83.



Comments