要求的處理方式

本文件說明 App Engine 應用程式如何接收要求及傳送回應。詳情請參閱要求標頭和回應參考資料

如果您的應用程式使用這些服務,則可以設定要求的位址,將要求傳送到特定服務或該服務的特定版本。如要進一步瞭解服務的轉送功能,請參閱要求的轉送方式

處理要求

您的應用程式負責啟動網路伺服器和處理要求。您可以使用您的開發語言適用的任何網路架構。

App Engine 收到應用程式的網路要求時,會叫用網址對應的 Servlet,如應用程式在 WEB-INF/ 目錄中的 web.xml 檔案所述。其支援 Java Servlet 2.5 或 3.1 API 規範,提供要求資料給 Servlet,然後接受回應資料。

App Engine 會執行應用程式的多個執行個體,每個執行個體都有各自用來處理要求的網路伺服器。每個要求都能轉送至任何執行個體,因此同個使用者發出的連續要求不一定會送至相同的執行個體。執行個體的數量可隨流量變化而自動調整。

根據預設,每個網路伺服器一次僅能處理一個要求。如要將多個要求平行分派至每一個網路伺服器,請在 appengine-web.xml 檔案中新增 <threadsafe>true</threadsafe> 元素,藉此將應用程式標示為執行緒安全。

下列 Servlet 類別範例會在使用者瀏覽器上顯示簡單訊息。

Java 8

// With @WebServlet annotation the webapp/WEB-INF/web.xml is no longer required.
@WebServlet(name = "requests", description = "Requests: Trivial request", urlPatterns = "/requests")
public class RequestsServlet extends HttpServlet {

  @Override
  public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
    resp.setContentType("text/plain");
    resp.getWriter().println("Hello, world");
  }
}

Java 7

public class RequestsServlet extends HttpServlet {
  @Override
  public void doGet(HttpServletRequest req, HttpServletResponse resp)
          throws IOException {
    resp.setContentType("text/plain");
    resp.getWriter().println("Hello, world");
  }
}

配額與限制

App Engine 會在流量增加時自動分配資源給您的應用程式。然而這項作業會受到下列限制:

  • App Engine 會為了低延遲時間 (回應要求的時間不到一秒) 的應用程式,保留自動調整資源配置的容量。如為具有高延遲時間 (例如在多個要求中,每個要求的回應時間超過一秒) 及高總處理量的應用程式,則需要白銀級、爍金級或白金級的支援。選用這類支援等級的客戶可與支援代表聯絡,要求提高總處理量上限。

  • 大幅受到 CPU 限制的應用程式可能也會產生一些額外的延遲時間,以便和相同伺服器上的其他應用程式有效率地共用資源。對靜態檔案的要求則不受這些延遲限制。

每個傳送至應用程式的要求均會計入「要求」限制,而回應要求所傳送的資料則會計入「連出頻寬 (可計費)」限制。

HTTP 及 HTTPS (加密連線) 要求均會計入「要求」、「連入頻寬 (可計費)」及「連出頻寬 (可計費)」的限制。GCP 主控台中的「Quota Details」(配額詳細資料) 頁面也會分別顯示「Secure Requests」(安全性要求)、「Secure Incoming Bandwidth」(安全連入頻寬) 和「Secure Outgoing Bandwidth」(安全連出頻寬) 的資料值,以便您查看。僅有 HTTPS 要求會計入這些值。詳情請參閱配額頁面。

下列限制專門適用於要求處理常式:

限制 數量
要求大小 32 MB
回應大小 32 MB
要求持續時間 60 秒
檔案總數量的上限 (應用程式檔案和靜態檔案) 總計 10,000 個
每個目錄 1,000 個
應用程式檔案的大小上限 32 MB
靜態檔案的大小上限 32 MB
所有應用程式和靜態檔案的全部大小上限 前 1 GB 免費
前 1 GB 過後,每個月每 GB $ 0.026

回應限制

動態回應限制為 32MB。如果指令碼處理常式產生大於此上限的回應,伺服器會傳回空白回應並顯示「500 Internal Server Error」(內部伺服器錯誤) 狀態碼。這項限制不適用於從 Blobstore 或 Cloud Storage 提供資料的回應。

要求標頭

傳入 HTTP 要求包含用戶端傳送的 HTTP 標頭。基於安全性考量,部分標頭在送達應用程式之前會由中繼 Proxy 進行處理或修改。

詳情請參閱要求標頭參考資料

要求回應

App Engine 會使用要求物件和回應物件來呼叫 Servlet,然後等待 Servlet 填入回應物件並回傳。Servlet 回傳時,回應物件上的資料會傳送給使用者。

您產生的回應會受到一些限制,而且在傳回用戶端前可能已經過修改。

詳情請參閱要求回應參考資料

串流回應

針對在處理要求時以增量區塊傳送給用戶端的資料,App Engine 不支援其串流回應。系統會依上述方式收集所有來自您程式碼的資料,並做為單一 HTTP 回應傳送。

回應壓縮

如果用戶端傳送含有原始要求的 HTTP 標頭,指出用戶端可接受壓縮 (使用 gzip 格式壓縮) 的內容,App Engine 會自動壓縮處理常式回應資料,並附加適當的回應標頭。它會同時使用 Accept-EncodingUser-Agent 要求標頭,以判斷用戶端是否能穩定接收壓縮的回應。

自訂用戶端可使用 gzip 值來指定 Accept-EncodingUser-Agent 標頭,藉此指出他們能夠接收壓縮的回應。回應的 Content-Type 也可用來判斷壓縮是否適當;一般來說,系統會壓縮文字內容類型,但不會壓縮二進位內容類型。

App Engine 自動壓縮回應時,會將 Content-Encoding 標頭新增至回應中。

指定要求期限

要求處理常式通常要在大約 60 秒的時間限制內對要求產生並傳回回應。期限一到,要求處理常式就會中斷。Java 執行階段環境會中斷 Servlet,方式為擲出 com.google.apphosting.api.DeadlineExceededException。如果沒有任何要求處理常式擷取到此例外情況,則執行階段環境會將「HTTP 500 伺服器錯誤」傳回用戶端。

如果有要求處理常式擷取到 DeadlineExceededException,則執行階段環境會給要求處理常式準備自訂回應的時間 (不到一秒)。發生例外情況後,如果要求處理常式準備自訂回應的時間超過一秒,則會產生 HardDeadlineExceededError

DeadlineExceededExceptionsHardDeadlineExceededErrors 均會強制終止要求並刪除執行個體。

如要瞭解期限截止前還有多少時間,應用程式可以匯入 com.google.apphosting.api.ApiProxy 並呼叫 ApiProxy.getCurrentEnvironment().getRemainingMillis()。如果應用程式打算啟動的工作可能需要過長的執行時間,則這項匯入及呼叫作業會非常有用;如果您知道一個工作單元的處理時間為五秒鐘,但 getRemainingMillis() 傳回的時間卻不到五秒,即沒必要啟動該工作單元。

雖然要求的回應時間最長可達 60 秒,但 App Engine 會針對要求停留時間短暫的應用程式進行最佳化,尤其是回應要求僅需耗費數百毫秒的應用程式。效率良好的應用程式能夠針對大部分的要求快速回應。而無法快速回應的應用程式,將無法隨著 App Engine 的基礎架構妥善調整規模。

如要瞭解常見的 DeadlineExceededError 肇因和建議的解決方法,請參閱處理 DeadlineExceededErrors 一文。

記錄

應用程式可以使用 java.util.logging.Logger 在應用程式記錄中寫入資訊。您可以在 GCP 主控台中使用 Stackdriver Logging 查看您應用程式的記錄資料。每個記錄的要求都有系統指派的要求 ID,這是根據要求開始時間編號的全域不重複 ID。GCP 主控台可辨識 Logger 類別的記錄層級,並交互顯示不同層級的訊息。

App Engine 可擷取 Servlet 寫入標準輸出串流 (System.out) 和標準錯誤串流 (System.err) 的所有資訊,並將資訊記錄在應用程式記錄中。寫入標準輸出串流的資料會以「INFO」層級記錄,而寫入標準錯誤串流的資料會以「WARNING」層級記錄。任何寫入輸出或錯誤串流的記錄架構 (例如 log4j) 皆可發揮作用,但如要更精細的控制 GCP 主控台中顯示的記錄層級,記錄架構必須使用 java.util.logging 轉接器。

Java 8

// With @WebServlet annotation the webapp/WEB-INF/web.xml is no longer required.
@WebServlet(
    name = "RequestLogging",
    description = "Requests: Logging example",
    urlPatterns = "/requests/log"
)
public class LoggingServlet extends HttpServlet {

  private static final Logger log = Logger.getLogger(LoggingServlet.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.");
    // ...
  }
}

Java 7

public class LoggingServlet extends HttpServlet {
  private static final Logger log = Logger.getLogger(LoggingServlet.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 的其他位置),然後將系統屬性 java.util.logging.config.file 複製到 "WEB-INF/logging.properties" (或您選擇的路徑,該路徑必須是應用程式根目錄的相對路徑)。您可以在 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>

Servlet 會使用 INFO 記錄層級來記錄訊息 (使用 log.info())。預設的記錄層級是 WARNING,此層級禁止輸出中包含 INFO 訊息。如要變更記錄層級,請編輯 logging.properties 檔案。如需設定記錄層級的具體範例,請參閱留言板表單應用程式。

環境

所有系統屬性和環境變數僅供應用程式使用,不對外公開。設定系統屬性僅會影響應用程式對該屬性的檢視,不會影響 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 是執行階段環境的版本 ID,例如 "1.3.0"。您可以叫用下列指令來取得版本:String version = SystemProperty.version.get();

  • 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

您可以使用下列程式碼來擷取處理要求的執行個體 ID:

com.google.apphosting.api.ApiProxy.getCurrentEnvironment().getAttributes().get("com.google.appengine.instance.id")

在實際工作環境中,登入的管理員可在下列網址中使用此 ID:http://[INSTANCE_ID].myApp.appspot.com/。要求會轉送至指定的執行個體。如果執行個體無法處理要求,則會立即傳回 503 錯誤。

要求 ID

提出要求時,您可以儲存不重複的要求 ID,以在稍後用於為要求與該要求的記錄建立關聯。

下列程式碼顯示如何在要求的內文中取得要求 ID:

com.google.apphosting.api.ApiProxy.getCurrentEnvironment().getAttributes().get("com.google.appengine.runtime.request_log_id")

本頁內容對您是否有任何幫助?請提供意見:

傳送您對下列選項的寶貴意見...

這個網頁
Java 適用的 App Engine 標準環境