App Engine はリクエストのドメイン名を使って、受信したリクエストがあなたのアプリケーション宛のものかを判断します。
http://your_app_id.appspot.com
のドメイン名を持つリクエストは、your_app_id
の部分をIDに持つアプリケーションにルーティングされます。 全てのアプリケーションは無料でappspot.com
ドメイン名を取得します。
appspot.com
ドメインはsubdomain-dot-your_app_id.appspot.com
形式のサブドメインをサポートしており、 ドメイン名の一部のsubdomain
部分には、(.
を除く)任意の文字列が使用されます。
この形式のサブドメイン宛のリクエストは、あなたのアプリケーションにルーティングされます。
Google Appsを使って、カスタムトップレベルドメインを設定できます。 Google Appsでは、あなたのビジネス用ドメインのサブドメインをGoogle メールやGoogle サイトのような様々なアプリケーションに割り当てることができます。 また、 App Engineアプリケーションをサブドメインに紐付けることもできます。 便宜上、Google AppsのドメインはアプリケーションIDを登録するタイミングで設定でき、それ以降は開発者コンソール上から設定できます。 詳細については Google Apps URLにあなたのアプリケーションを配置する を参照してください。
これらURL宛のリクエストは全て、あなたが開発者コンソール上で既定として選んだバージョンのアプリケーションへ送られます。 各バージョンのアプリケーションはそれぞれ独自のURLを持っているので、新しいバージョンのアプリを既定バージョンにはせずに配置したりテストしたりできます。 バージョン固有のURLは、appspot.com
ドメイン名に加えて、アプリの設定ファイルに書かれたバージョン識別子を使って生成されます。 このように: http://version_id-dot-latest-dot-your_app_id.appspot.com
。 また、バージョン固有URLの付いたサブドメインを使用することもできます。: http://subdomain-dot-version_id-dot-latest-dot-your_app_id.appspot.com
リクエストで使用されているドメイン名は、アプリケーションに渡されるリクエストデータ内に含まれています。 アプリへのアクセスに使用されているドメイン名に応じてアプリで異なる応答をさせたい場合は (特定のドメインへのアクセスを制限したり、公式のドメインへリダイレクトするような)、 アプリケーションコード内でのドメイン宛のリクエストデータ( Host
リクエストヘッダのような)を確認し、それに応じて応答することができます。
あなたのアプリが モジュールを使用している場合、リクエストを特定のモジュール(必要に応じてそのモジュールの特定のバージョン)に割り振ることができます。 モジュールのアドレス指定に関する詳細情報については、リクエストをモジュールへルーティングするを参照してください。
注意:
2013年4月以降から、 Google ではappspot.com
でホストされたダブルワイルドカードドメイン(すなわち、*.*.appspot.com
)向けのSSL証明書は発行しません。
アプリケーションへのHTTPSアクセスにそうしたURLを使用している場合は、アプリケーションのロジックを".
"ではなく"-dot-
"を使ったものに変更してください。
例えば、アプリケーションmyapp のv1にアクセスするにはhttps://v1-dot-myapp.appspot.com
を使用します。
https://v1.myapp.appspot.com
を使用した場合は証明書が一致せず、URLと証明書が正確に一致することを想定しているUser-Agentではエラーが発生します。
App Engine があなたのアプリケーション宛のウェブリクエストを受信した時、
アプリケーションのデプロイメントディスクリプタ(WEB-INF/
ディレクトリ内のweb.xml
ファイル)で説明しているように、宛先URLに対応したサーブレットを実行します。
App Engineは、サーブレット宛のリクエストデータを提供したり応答データを受信するためにJava Servlet APIバージョン2.5を使用しています。
App Engine はアプリケーションのインスタンスを複数実行し、各インスタンスはリクエストを処理するために独自のウェブサーバを持っています。 リクエストは任意のインスタンスにルーティングされ、同一ユーザーからリクエスト連続してきても、常に同じインスタンスに送られるとは限りません。 インスタンスの数は、トラフィック数の変化に応じて自動的に調節されます。
既定では、各ウェブサーバは一度に一つのリクエストのみを処理します。
アプリケーションをスレッドセーフに設定した場合、App Engineは複数のリクエストを各ウェブサーバに平行して割り振ることができます。
そのやり方は、同時リクエストを使用するで説明しているように、 appengine-web.xml
に<threadsafe>true</threadsafe>
エレメントを追加するだけです。
以下は、servlet クラスでユーザーのウェブブラウザに簡単なメッセージを表示する例になります。
import java.io.IOException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyServlet extends HttpServlet {
@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
resp.setContentType("text/plain");
resp.getWriter().println("Hello, world");
}
}
受信した HTTP リクエストには、クライアントによって送信された HTTP ヘッダが含まれています。 安全上の理由から、ヘッダによってはアプリケーションに届く前に中間プロキシによってサニタイズされたり修正されたりします。
以下のヘッダはリクエストから削除されます。:
Accept-Encoding
Connection
Keep-Alive
Proxy-Authorization
TE
Trailer
Transfer-Encoding
また、appspot.com
や *.appspot.com
以外のドメインへ送られるリクエストからはStrict-Transport-Security
ヘッダが削除されます。
これらのヘッダはクライアントとサーバ間のHTTPデータ転送に関連し、アプリケーション側ではノータッチの領域です。 例えば、サーバはAccept-Encoding
リクエストヘッダの値に従って、自動的にgzip圧縮された応答を送信することがあります。 アプリケーション自身は、ユーザー受信できるコンテンツエンコードが何なのかを知る必要はありません。
アプリを動作させるために、App Engine は全てのリクエストに対して以下のヘッダを追加します:
X-AppEngine-Country
X-AppEngine-Country
ヘッダに記載された国情報は異なる可能性もあります。 アプリケーションでは、特別な国コード ZZ
(不明の国)も処理できるようにしてください。
X-AppEngine-Region
X-AppEngine-Country
の示す国と照らし合わせないと意味が分かりません。 例えば、国が"US"で地域が"ca"の場合は、 "ca"は"カリフォルニア"を意味します。カナダではありません。 有効な地域の値の全一覧は、 ISO-3166-2標準にあります。
X-AppEngine-City
mountain view
となるでしょう。
このヘッダについては、有効な値の一覧はありません。
X-AppEngine-CityLatLong
App Engineサービスでは必要に応じてリクエストヘッダを追加することもあります:
タスクキューサービスでは、リクエスト内のタスクとそれに関連するキューの詳細を伝えるために、リクエストに 追加ヘッダ を追加します。
Cron サービスからのリクエストにも以下の HTTP ヘッダが含まれます:
X-AppEngine-Cron: true
詳細については cronのURLのセキュリティを保護する を参照してください。
他のApp Engine アプリケーションから来たリクエストには、リクエストを作成したアプリを識別するための以下ヘッダが含まれています。:
X-Appengine-Inbound-Appid
詳細についてはアプリ識別のドキュメント を参照してください。
App Engine はrequest オブジェクトと response オブジェクトを持つサーブレットを呼び出し、サーブレットがresponse オブジェクトを埋め込んだ応答を返すのを待ちます。 サーブレットから応答が返った時、response オブジェクトのデータがユーザーに送信されます。
以降で説明するように、応答を生成する際にはいくつかの制限が適用され、応答がクライアントへ返される前に変更されることもあります。
動的な応答のサイズは32MBに制限されています。スクリプトハンドラーがこの制限以上の応答を生成した場合、サーバは500 Internal Server Error ステータスコードの空応答を返します。 この制限はBlobstore やGoogle クラウドストレージから届くデータの応答には適用されません。
App Engine では、リクエストを処理しながらクライアントへ増加チャンクのデータを送信する、ストリーミング応答はサポートしていません。 あなたのコードから送信される全てのデータは上記で説明されている方法で収集され、単一のHTTP応答として送信されます。
クライアントが、圧縮(gzipped)コンテンツを受信できることを示すHTTPヘッダをリクエストに付けて送信した場合、 App Engine は自動的にハンドラー応答データを圧縮し、適切な応答ヘッダを付けます。
クライアントが圧縮応答を確実に受け取ることができるかを判別するために、Accept-Encoding
リクエストヘッダとUser-Agent
リクエストヘッダの両方を使用します。
クライアントを改造する際には、Accept-Encoding
ヘッダとUser-Agent
ヘッダの両方にgzip
の値を指定することで、クライアントが圧縮された応答を受信できることを相手に伝えることができます。
また、応答のContent-Type
は圧縮が適切かどうかは判別するために使用されます。;一般的には、テキストベースのコンテンツは圧縮されますがバイナリのコンテンツは圧縮されません。
App Engineによって応答が自動的に圧縮された場合、応答には Content-Encoding
ヘッダが追加されます。
以下のヘッダは無視され、応答から削除されます:
Connection
Content-Encoding
*Content-Length
Date
Keep-Alive
Proxy-Authenticate
Server
Trailer
Transfer-Encoding
Upgrade
* App Engineによって応答が圧縮される場合は再追加されることがあります。
さらに、*.appspot.com
以外のドメインが送信する応答からはStrict-Transport-Security
ヘッダが削除されます。
名前や値にASCII ではない文字を含むヘッダも削除されます。
以下のヘッダは応答では追加や置き換えが行われます:
Cache-Control
と Expires
と Vary
これらのヘッダでは、プロキシ(インターネットサービスプロバイダーのような)とブラウザを中間媒体とするキャッシュポリシーを設定します。 あなたのスクリプトがこれらのヘッダを設定した場合、応答にSet-Cookieヘッダが設定されるか管理者アカウントを使って署名したユーザー向けに応答が生成されない限りは、キャッシュは維持されたままになります。
静的ハンドラーは 設定ファイルに従ってこれらのヘッダを設定します。 あなたがCache-Control
を設定しない場合は、サーバでprivate
の値を設定して、Vary: Accept-Encoding
ヘッダを追加します。
応答にSet-Cookieヘッダが設定されていた場合、Cache-Control
ヘッダには private
の値が設定され(既にprivateよりも厳しいアクセス権が設定されていないのであれば)、
Expires
ヘッダには現在の日時が設定されるでしょう (それが過去の日付でなければ)。通常はこれでブラウザは応答をキャッシュできますが、プロキシサーバではキャッシュを行いません。これにはセキュリティ上の理由があります。応答のキャッシュを公に行うと、別のユーザーが同じリソースに続けざまにリクエストを送信して最初のユーザーのクッキーを取得できてしまうからです。
Content-Encoding
Content-Type
によっては、前述のようにサーバは応答の本文を自動的に圧縮します。
この場合は、 Content-Encoding: gzip
ヘッダを追加すると本文が圧縮されることを表します。
詳細については応答の圧縮の項目を参照してください。Content-Length
や Transfer-Encoding
Content-Length
ヘッダを常に無視します。
Content-Length
には本文の長さ(圧縮が適用される場合は圧縮後の長さ)が設定されるか、もしくはContent-Length
が削除されます。
チャンク転送エンコーディング を使用します(Transfer-Encoding: chunked
ヘッダが追加されます)。Content-Type
アプリケーションによって設定されなかった場合、サーバは既定の Content-Type: text/html
ヘッダを設定します。
Date
Server
Google Frontend
の値が設定されます。
管理者アカウントでログインした状態であなたのサイトにアクセスした場合、App Engineは応答ヘッダ内にリクエストごとの統計情報を入れます:
X-AppEngine-Estimated-CPM-US-Dollars
X-AppEngine-Resource-Usage
リソース消費統計情報を含んだ応答はキャッシュできません。
アプリケーションの応答に X-AppEngine-BlobKey
ヘッダが設定されている場合、オプションのX-AppEngine-BlobRange
ヘッダと合わせて、
blobstore blobのコンテンツの一部または全部で本文を書き換えるのに使われます。
アプリケーションでContent-Type
を設定しない場合、BLOB のMIME タイプが設定されます。
Range が必要な場合は、応答ステータスは206 Partial Content
に変更され、Content-Range
ヘッダが追加されます。
X-AppEngine-BlobKey
ヘッダと X-AppEngine-BlobRange
ヘッダは応答から削除されます。
blobstore_handlers.BlobstoreDownloadHandler
クラスがそれらヘッダを設定するので、通常はあなたが自分で設定する必要はありません。
詳細については Blobを使用するを参照してください。
カスタムHTTP 応答ヘッダは、アプリケーションの設定ファイルにて、動的および静的なURLごとに設定できます。
詳細については 設定ドキュメント にあるhttp_headers
の項目を参照してください。
リクエストハンドラーには、リクエストに対して応答を生成したり返したりする際に時間制限があります。 一般的にはだいたい60秒です。期限を超過すると、リクエストハンドラーは中断されます。
Java ランタイム環境では、 com.google.apphosting.api.DeadlineExceededException
を発生させることでサーブレットを中断させます。
この例外をキャッチできるリクエストハンドラがない場合、ランタイム環境はクライアントへHTTP 500サーバエラーを返します。
リクエストハンドラがあってDeadlineExceededException
がキャッチされた場合、ランタイム環境はリクエストハンドラに対してカスタム応答を作成する時間(一秒未満)を与えます。
例外が発生してからカスタム応答を作成するまでに一秒以上かかった場合、HardDeadlineExceededError
が発生します。
DeadlineExceededExceptions
やHardDeadlineExceededErrors
が発生すると、強制的にリクエストは終了されインスタンスは破棄されます。
制限時間までにどれだけの猶予が残っているかを調べるために、アプリケーションは com.google.apphosting.api.ApiProxy
をインポートしてApiProxy.getCurrentEnvironment().getRemainingMillis()
を呼び出すことができます。
これは、アプリケーションが時間がかかるかもしれない処理の開始を予定している場合に便利です; ある作業の処理に5秒かかるがgetRemainingMillis()
の戻り値が5秒未満だった場合は、その作業を開始しても意味がありません。
リクエストが応答を返すまでには60秒の猶予時間がありますが、App Engineはリクエストの生存時間が短いアプリケーション(通常は数百ミリ秒)向けに最適化されています。 効率的なアプリは、ほとんどのリクエストに対して迅速に応答します。 迅速に応答しないアプリは、App Engineのインフラ上で上手く拡張できません。
一般的なDeadlineExceededError の原因と推奨される対処方法についてはDeadlineExceededErrorsに対処するを参照してください。
バックエンドを使用することで、このリクエストタイマーを回避できます。; バックエンドではリクエストの生成や応答について時間制限がありません。
SPDYをサポートしているブラウザがSSL経由でアクセスした場合、App Engineアプリケーションは自動的に SPDY プロトコルを使用します。 これはHTTP の代わりとしてGoogleがデザインしたもので、ウェブページのダウンロードの待ち時間を減らすためのものです。 SPDY を使用しても、アプリケーションとユーザーの両方でそのことを意識する必要はありません(普通のHTTPを使っているかのように、アプリケーションを記述できます)。 詳細情報についてはSPDY プロジェクトのページを参照してください。
アプリケーションは、java.util.logging.Loggerを使ってアプリケーションログへ情報を記述することができます。
あなたのアプリケーションのログデータは開発者コンソールのログページで閲覧したり、 appcfg.sh request_logsを使ってダウンロードすることができます。
ログに記録された各リクエストにはrequest IDが割り振られます。
request_idはリクエストの開始時間を基に生成された世界で唯一の識別子です。
開発者コンソールは Logger
クラスのログレベルを認識できるので、異なるレベルのメッセージの表示を切り替えることができます。
サーブレットが標準出力ストリーム(System.out
) と標準エラーストリーム(System.err
)に書き出したものは全て App Engine にキャプチャされ、
アプリケーションログに記録されます。
標準出力ストリームに書き出された行は"INFO"レベルでログに記録され、
標準エラーストリームに書き出された行は "WARNING" レベルでログに記録されます。
出力ストリームやエラーストリームにログを記録するログフレームワーク(log4jのような)は正常に動作します。
しかし、開発者コンソールのログレベルの操作をよりきめ細かく表示するために、ログフレームワークではjava.util.logging
アダプターを使用しなればなりません。
import java.util.logging.Logger;
// ...
public class MyServlet extends HttpServlet {
private static final Logger log = Logger.getLogger(MyServlet.class.getName());
@Override
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
log.info("An informational message.");
log.warning("A warning message.");
log.severe("An error message.");
}
}
App Engine Java SDK には、appengine-java-sdk/config/user/
ディレクトリに logging.properties
のテンプレートファイルが含まれています。
これを使用するには、このファイルをWEB-INF/classes
ディレクトリ(もしくは WAR内のどこか)にコピーし、
then the system property java.util.logging.config.file
to "WEB-INF/logging.properties"
(or whichever path you choose, relative to the application root).
appengine-web.xml
ファイルのシステムプロパティを以下のように設定できます。:
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
...
<system-properties>
<property name="java.util.logging.config.file" value="WEB-INF/logging.properties" />
</system-properties>
</appengine-web-app>
サーブレットはINFO
ログレベルを使って (log.info()
を使って)メッセージをログに記録します。
The default log level is WARNING
, which suppresses INFO
messages from the output. ログレベルを変更するには、 logging.properties
ファイルを編集します。
ログレベルの設定する具体的な例についてはGuestbook のフォームアプリケーションを参照してください。
Eclipse 用 Google プラグインの新しいプロジェクトウィザードでは、自動的にあなたに代わってこれらログ設定ファイルを作成してWEB-INF/classes/
へコピーします。
java.util.logging
のために、このファイルを使ってシステムプロパティを設定しなければなりません。
全てのシステムプロティと環境変数はあなたのアプリケーションに対してprivateです。 システムプロパティを設定するとあなたのアプリケーションからのプロパティ参照にのみ影響を与え、JVMからのプロパティ参照には影響しません。
デプロイメントディスクリプタであなたのアプリのシステムプロパティと環境変数を設定できます。
App Engine はランタイムを識別するためのいくつかの環境変数を設定します:
App Engine上で動作している場合はcom.google.appengine.runtime.environment
の値は"Production"
となり、
デベロップメントサーバ上で動作している場合には"Development"
となります。
System.getProperty()
の使用以外にも、我々のtype-safe APIを使ってシステムプロパティにアクセスすることができます。例えば:
if (SystemProperty.environment.value() ==
SystemProperty.Environment.Value.Production) {
// The app is running on App Engine...
}
com.google.appengine.runtime.version
の値は、 "1.3.0"
のようなランタイム環境のバージョン ID です。
以下を実行することでバージョン情報を取得できます: String version = SystemProperty.version.get();
<
/p>
com.google.appengine.application.id
の値はアプリケーションIDです。以下を実行することで ID を取得できます: String ID = SystemProperty.applicationId.get();
com.google.appengine.application.version
は現在実行しているアプリケーションモジュールのメジャーバージョンとマイナーバージョンを "X.Y"形式で表します。
メジャーバージョンの数字("X")はモジュールのappengine-web.xmlファイルで設定されます。
マイナーバージョンの数字("Y") は、各バージョンのアプリがApp Engineにアップロードされた時に自動的に設定されます。
以下を事項することでIDを取得できます: String ID = SystemProperty.applicationVersion.get();
開発ウェブサーバ上では、取得されるメジャーバージョンは常に既定のモジュールのバージョンになり、マイナーバージョンでは常に "1"になります。
App Engine がアプリサーバ上のJVMを初期化する時、以下のシステムプロパティも設定します。:
file.separator
path.separator
line.separator
java.version
java.vendor
java.vendor.url
java.class.version
java.specification.version
java.specification.vendor
java.specification.name
java.vm.vendor
java.vm.name
java.vm.specification.version
java.vm.specification.vendor
java.vm.specification.name
user.dir
以下のコードを使って、リクエストを処理しているインスタンスのIDを取得できます。:
com.google.apphosting.api.ApiProxy.getCurrentEnvironment().getAttributes().get("com.google.appengine.instance.id")
製品版の環境では、ログイン状態の管理者はurl: http://[INSTANCE_ID].myApp.appspot.com/
にこのIDを使用できます。
するとリクエストはURLで指定したインスタンスにルーティングされます。
インスタンスがリクエストを処理できない場合は即座に503を返します。
リクエスト時には、リクエストに対してユニークに割り振られたリクエストIDを保存できます。 リクエストIDは、後でリクエストとリクエストのログを紐付けるのに使用できます。
以下のコードは、リクエストのコンテクスト内でリクエストIDを取得する方法です:
com.google.apphosting.api.ApiProxy.getCurrentEnvironment().getAttributes().get("com.google.appengine.runtime.request_log_id")
Google App Engine ではトラフィックの増加に応じてあなたのアプリケーションに自動的にリソースを割り当てます。 しかし、それには以下の制限があります。:
アプリケーションが受信した各リクエストは、リクエスト 制限にカウントされます。 リクエストに対する応答で送信されたデータは送信帯域幅 (課金可能)制限にカウントされます。
HTTPリクエスト とHTTPS (安全な)リクエストは両方とも リクエスト制限と受信帯域幅 (課金可能)制限と 送信帯域幅 (課金可能) 制限にカウントされます。 開発者コンソールの割り当て量の詳細ページでも情報提供のために別の値として セキュアリクエストとセキュア受信帯域幅と セキュア送信帯域幅を報告します。 HTTPSリクエストのみがこれらの値にカウントされます。詳細情報については割り当て量ページを参照してください。
システム全体の安全制限に加えて、以下の制限がリクエストハンドラの使用時に適用されます。:
制限 | 制限値 |
---|---|
リクエストサイズ | 32 メガバイト |
応答サイズ | 32 メガバイト |
リクエスト時間 | 60 秒 |
ファイル(アプリケーションファイルと静的ファイル)の最大数 | 合計10,000 ディレクトリごとに1,000 |
アプリケーションファイルの最大サイズ | 32 メガバイト |
静的ファイルの最大サイズ | 32 メガバイト |
全てのアプリケーションファイルと静的ファイルの最大合計サイズ | 最初の1ギガバイトは無料 それを超えると1ギガバイトあたり月額 $ 0.026 |