Migrazione delle richieste in uscita

Per impostazione predefinita, il runtime di Python 2.7 utilizza il servizio di recupero dell'URL per gestire le richieste HTTP(S) in uscita, anche se utilizzi le librerie Python urllib, urllib2 o httplib per inviare queste richieste. Il recupero URL non gestisce richieste dalla libreria requests a meno che tu non fornisca esplicitamente abilitarlo.

Il runtime Python 3 non ha bisogno di un servizio intermedio per gestire le richieste in uscita. Se vuoi eseguire la migrazione dall'utilizzo delle API URL Fetch, ma hai ancora bisogno di funzionalità simili, devi eseguire la migrazione di queste richieste in modo da utilizzare una libreria Python standard come la libreria requests.

Differenze principali tra URL Fetch e le librerie Python standard

  • Il limite di dimensione e le quote per le richieste gestite da URL Fetch sono diversi dal limite di dimensione e dalle quote per le richieste non gestite da URL Fetch.

  • Con il recupero URL, quando la tua app invia una richiesta a un'altra app di App Engine, Il recupero URL aggiunge l'intestazione della richiesta X-Appengine-Inbound-Appid per dichiarare l'identità dell'app. L'app che riceve la richiesta può utilizzare l'identità per determinare se deve elaborare la richiesta.

    Questa intestazione è disponibile solo nelle richieste inviate dalla tua app se utilizza il recupero URL. App Engine rimuove l'intestazione se tu o una terza parte la aggiungete a una richiesta.

    Per informazioni sull'asserzione e sulla verifica dell'identità senza utilizzare il recupero degli URL, consulta Migrazione dell'identità delle app ai token ID OIDC.

    Per un esempio di come utilizzare l'intestazione della richiesta per verificare l'identità dell'app chiamante quando le richieste vengono inviate tra app App Engine, consulta Esempio di richiesta da App Engine ad App Engine.

  • Puoi utilizzare il metodo di recupero URL per impostare timeout predefinito per tutte le richieste. La maggior parte delle librerie Python 3, come requests e urllib, imposta il timeout predefinito a None, quindi devi aggiornare ogni richiesta effettuata dal tuo codice per specificare timeout.

Panoramica del processo di migrazione

  1. Se la tua app utilizza le API di recupero URL per effettuare le richieste, aggiorna il codice utilizzare invece una libreria Python standard. Ti consigliamo di specificare un timeout per ogni richiesta.

  2. Testa le richieste in uscita nel server di sviluppo locale.

  3. Configura la tua app in modo da ignorare il recupero URL quando viene eseguita in in App Engine.

  4. Esegui il deployment della tua app.

Sostituzione delle API di recupero URL con una libreria Python

  1. Se non stai già utilizzando una libreria Python standard per inviare messaggi in uscita richieste, scegli una libreria e aggiungila alle dipendenze dell'app.

    Ad esempio, per utilizzare la libreria Requests, crea un file requirements.txt nella stessa cartella del file app.yaml e aggiungi la seguente riga:

    requests==2.24.0
    

    Per la compatibilità con Python 2, ti consigliamo di fissare la libreria requests alla versione 2.24.0. Quando esegui il deployment dell'app, App Engine scarica tutte le dipendenze definite nel file requirements.txt.

    Per lo sviluppo locale, ti consigliamo di installare le dipendenze in un ambiente virtuale come venv.

  2. Cerca il tuo codice per qualsiasi uso di google.appengine.api.urlfetch e aggiornare il codice per utilizzare la libreria Python.

Eseguire richieste HTTPS semplici

L'esempio seguente mostra come effettuare una richiesta HTTPS standard utilizzando la libreria requests:

# 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)

Invio di richieste HTTPS asincrone

L'esempio seguente mostra come effettuare una richiesta HTTPS asincrona utilizzando la libreria requests:

# 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,
    )


Test in locale

Se hai aggiornato una delle richieste in uscita, esegui l'app nella server di sviluppo locale e verificare che le richieste vadano a buon fine.

Aggirare il recupero degli URL

Per interrompere la gestione delle richieste dal recupero URL quando esegui il deployment dell'app in App Engine:

  1. Nel file app.yaml, imposta l'ambiente GAE_USE_SOCKETS_HTTPLIB variabile con qualsiasi valore. Il valore può essere qualsiasi valore, inclusa una stringa vuota. Ad esempio:

    env_variables:
      GAE_USE_SOCKETS_HTTPLIB : ''
    
  2. Se hai attivato il recupero di URL per gestire le richieste inviate dalla raccolta requests, puoi rimuovere la sezione Richieste AppEngineAdapter dalla tua app.

    Ad esempio, rimuovi requests_toolbelt.adapters.appengine dal appengine_config.py file e requests_toolbelt.adapters.appengine.monkeypatch() dai file Python.

Tieni presente che, anche se ignori URL Fetch come descritto nei passaggi precedenti, la tua app può comunque utilizzare direttamente l'API URL Fetch.

Deployment dell'app

Quando è tutto pronto per il deployment dell'app, devi:

  1. Testa l'app su App Engine.

    Visualizza la pagina Quote di App Engine nella console Google Cloud per verificare che la tua app non effettui chiamate API Url Fetch.

    Visualizzare le chiamate all'API URL Fetch

  2. Se l'app viene eseguita senza errori, utilizza il traffico da dividere in lentamente aumentare il traffico per la tua app aggiornata. Monitora attentamente l'app per individuare prima di indirizzare una quantità maggiore di traffico all'app aggiornata.