Ausgehende Anfragen migrieren

Standardmäßig verwendet die Python 2.7-Laufzeit den URL-Abrufdienst., um ausgehende HTTP(S)-Anfragen zu verarbeiten, auch wenn Sie die urllib-. urllib2- oder httplib-Python-Bibliotheken verwenden, um diese Anfragen zu stellen. Der URL-Abruf verarbeitet keine Anfragen aus der Bibliothek requests, es sei denn, Sie aktivieren sie ausdrücklich.

Die Python 3-Laufzeit benötigt keinen Vermittlerdienst, um ausgehende Anfragen zu verarbeiten. Wenn Sie die Verwendung von URL Fetch APIs vermeiden möchten, aber ähnliche Funktionen benötigen, sollten Sie diese Anfragen migrieren, um eine Standard-Python-Bibliothek wie die requests-Bibliothek zu verwenden.

Hauptunterschiede zwischen URL-Abruf und Python-Standardbibliotheken

  • Die Seite Größenbeschränkung und Kontingente für Anfragen, die mit URL-Abruf verarbeitet werden, unterscheiden sich von der Größenbeschränkung und den Kontingenten für Anfragen, die nicht vom URL-Abruf verarbeitet werden.

  • Wenn beim URL-Abruf eine Anfrage an eine andere App Engine-Anwendung gesendet wird, fügt URL Fetch den Anfrage-Header X-Appengine-Inbound-Appid hinzu, um die Identität der Anwendung zu bestätigen. Die Anwendung, die die Anfrage empfängt, kann dann anhand der Identität bestimmen, ob die Anfrage verarbeitet werden soll.

    Dieser Header ist nur in Anfragen verfügbar, die von Ihrer Anwendung gesendet werden, wenn URL Fetch verwendet wird. App Engine entfernt den Header, wenn Sie oder ein Drittanbieter ihn zu einer Anfrage hinzufügen.

    Informationen dazu, wie Sie die Identität ohne URL-Abruf bestätigen und bestätigen, finden Sie unter App Identity zu OIDC-ID-Tokens migrieren.

    Ein Beispiel für die Verwendung des Anfrageheaders zum Prüfen der Identität der aufrufenden Anwendung, wenn Anfragen zwischen App Engine-Anwendungen gesendet werden, finden Sie unter Anfragebeispiel für App Engine-zu-App Engine-Anfragen.

  • Sie können URL-Abruf verwenden, um ein Standard-Zeitlimit für alle Anfragen festzulegen. Die meisten Python 3-Bibliotheken wie requests und urllib setzen die Standardzeitüberschreitung auf None. Daher sollten Sie jede Anfrage aktualisieren, die Ihr Code ausführt, um ein Zeitlimit festzulegen.

Übersicht über den Migrationsprozess

  1. Wenn Ihre Anwendung URL Fetch APIs für Anfragen verwendet, aktualisieren Sie Ihren Code, um stattdessen eine Python-Standardbibliothek zu verwenden. Wir empfehlen, für jede Anfrage eine Zeitüberschreitung festzulegen.

  2. Testen Sie Ihre ausgehenden Anfragen auf dem lokalen Entwicklungsserver.

  3. Konfigurieren Sie Ihre App so, dass der URL-Abruf bei der Ausführung in App Engine umgangen wird.

  4. Anwendung bereitstellen

URL Fetch APIs durch eine Python-Bibliothek ersetzen

  1. Wenn Sie noch keine standardmäßige Python-Bibliothek zum Senden ausgehender Anfragen verwenden, wählen Sie eine Bibliothek aus und fügen Sie sie den Abhängigkeiten Ihrer Anwendung hinzu.

    Wenn Sie beispielsweise die Bibliothek "Anfragen" verwenden möchten, erstellen Sie eine Datei requirements.txt in demselben Ordner wie die Datei app.yaml und fügen Sie folgende Zeile hinzu:

    requests==2.24.0
    

    Aus Gründen der Kompatibilität mit Python 2 empfehlen wir, die requests-Bibliothek an Version 2.24.0 anzuheften. Wenn Sie Ihre Anwendung bereitstellen, lädt App Engine alle Abhängigkeiten herunter, die in der Datei requirements.txt definiert sind.

    Für die lokale Entwicklung empfehlen wir, Abhängigkeiten in einer virtuellen Umgebung wie venv zu installieren.

  2. Suchen Sie in Ihrem Code nach einer beliebigen Verwendung des Moduls google.appengine.api.urlfetch und aktualisieren Sie den Code so, dass er Ihre Python-Bibliothek verwendet.

Einfache HTTPS-Anfragen stellen

Das folgende Beispiel zeigt, wie Sie mithilfe der Bibliothek requests eine Standard-HTTPS-Anfrage stellen:

# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import logging

from flask import Flask

import requests

app = Flask(__name__)

@app.route('/')
def index():
    url = 'http://www.google.com/humans.txt'
    response = requests.get(url)
    response.raise_for_status()
    return response.text

@app.errorhandler(500)
def server_error(e):
    logging.exception('An error occurred during a request.')
    return """
    An internal error occurred: <pre>{}</pre>
    See logs for full stacktrace.
    """.format(e), 500

if __name__ == '__main__':
    # This is used when running locally.
    app.run(host='127.0.0.1', port=8080, debug=True)

Asynchrone HTTPS-Anfragen ausführen

Das folgende Beispiel zeigt, wie Sie mithilfe der requests-Bibliothek eine asynchrone HTTPS-Anfrage stellen:

# Copyright 2020 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import logging

from flask import Flask, make_response

from requests_futures.sessions import FuturesSession
from time import sleep

TIMEOUT = 10    # Wait this many seconds for background calls to finish
app = Flask(__name__)

@app.route('/')     # Fetch and return remote page asynchronously
def get_async():
    session = FuturesSession()
    url = 'http://www.google.com/humans.txt'

    rpc = session.get(url)

    # ... do other things ...

    resp = make_response(rpc.result().text)
    resp.headers['Content-type'] = 'text/plain'
    return resp

@app.route('/callback')     # Fetch and return remote pages using callback
def get_callback():
    global response_text
    global counter

    response_text = ''
    counter = 0

    def cb(resp, *args, **kwargs):
        global response_text
        global counter

        if 300 <= resp.status_code < 400:
            return  # ignore intermediate redirection responses

        counter += 1
        response_text += 'Response number {} is {} bytes from {}\n'.format(
            counter, len(resp.text), resp.url)

    session = FuturesSession()
    urls = [
        'https://google.com/',
        'https://www.google.com/humans.txt',
        'https://www.github.com',
        'https://www.travis-ci.org'
    ]

    futures = [session.get(url, hooks={'response': cb}) for url in urls]

    # No wait functionality in requests_futures, so check every second to
    # see if all callbacks are done, up to TIMEOUT seconds
    for elapsed_time in range(TIMEOUT+1):
        all_done = True
        for future in futures:
            if not future.done():
                all_done = False
                break
        if all_done:
            break
        sleep(1)

    resp = make_response(response_text)
    resp.headers['Content-type'] = 'text/plain'
    return resp

@app.errorhandler(500)
def server_error(e):
    logging.exception('An error occurred during a request.')
    return """
    An internal error occurred: <pre>{}</pre>
    See logs for full stacktrace.
    """.format(e), 500

Anwendung lokal testen

Wenn Sie eine Ihrer ausgehenden Anfragen aktualisiert haben, führen Sie Ihre Anwendung auf dem lokalen Entwicklungsserver aus und prüfen Sie, ob die Anfragen erfolgreich sind.

URL-Abruf umgehen

So verhindern Sie, dass beim URL-Abruf Anfragen beim Bereitstellen der Anwendung in App Engine verarbeitet werden:

  1. Legen Sie in der Datei app.yaml die Umgebungsvariable GAE_USE_SOCKETS_HTTPLIB auf einen beliebigen Wert fest. Der Wert kann beliebig sein (auch ein leerer String). Beispiel:

    env_variables:
      GAE_USE_SOCKETS_HTTPLIB : ''
    
  2. Wenn Sie den URL-Abruf zur Verarbeitung von Anfragen aktiviert haben, die aus der Bibliothek requests gesendet wurden, können Sie die Anfragen AppEngineAdapter aus der Anwendung entfernen.

    Entfernen Sie beispielsweise requests_toolbelt.adapters.appengine aus Ihrer appengine_config.py-Datei und requests_toolbelt.adapters.appengine.monkeypatch() aus Ihren Python-Dateien.

Selbst wenn Sie den URL-Abruf wie in den vorherigen Schritten beschrieben umgehen, kann die Anwendung weiterhin die URL Fetch API verwenden.

Anwendung bereitstellen

Sobald Sie Ihre App bereitstellen können, sollten Sie:

  1. Testen Sie die Anwendung in App Engine.

    Rufen Sie in der Google Cloud Console die Seite "App Engine-Kontingente" auf, um zu prüfen, ob Ihre Anwendung keine URL-Abruf-API-Aufrufe durchführt.

    URL Fetch API-Aufrufe aufrufen

  2. Wenn die Anwendung fehlerfrei ausgeführt wird, verwenden Sie die Trafficaufteilung, um den Traffic für die aktualisierte Anwendung langsam hochzufahren. Prüfen Sie die Anwendung sorgfältig auf mögliche Probleme, bevor Sie mehr Traffic zur aktualisierten Anwendung leiten.