Function Compute で Python を使用するには、Python 関数をハンドラとして定義する必要があります。現在の Python ランタイム環境では、共通ハンドラ または HTTP トリガーハンドラ をサポートしています。HTTP トリガーを使用すると、HTTP リクエストをより効率的に処理できます。HTTP トリガーを持つハンドラを除き、他のすべての Python でコーディングされた関数ハンドラは同じです。
現在、Function Compute は Python 2.7 (runtime = python2.7) と Python 3.6 (runtime = python3) をサポートしています。詳細は、「Python ランタイム環境」 をご参照ください。
内容
このトピックでは、共通ハンドラ、および HTTP トリガーハンドラについて説明します。
共通ハンドラ
簡単な関数の定義は次のとおりです。
def my_handler(event, context):
return 'hello world'
関数名
my_handler
: 関数名は、関数が生成されるときに定義される “handler” フィールドと一致しなければなりません。たとえば、handler がmain.my_handler
と指定された場合、Function Compute はmain.py
で定義されたmy_handler
関数を取得します。
event パラメーター
- event パラメーターは、関数を呼び出すときに渡されます。Python 2.7 では、このパラメーターは
str
型です。Python 3 ではbytes
型です。関数の入力パラメーターです。 - このパラメーターは、関数によって解析しません。処理の必要に応じて変換できます。たとえば、JSON 文字列が渡された場合、パラメーターを
dict
型に変換できます。例:定義済み event:
関数コード:{
"key": "value"
}
value パラメーターが返されます。# -*- coding: utf-8 -*-
import json
def my_handler(event, context):
evt = json.loads(event)
return evt['key']
context パラメーター
- context パラメーターには、関数が実行されるときに生成されるリクエスト ID や一時的な AccessKey などの情報が含まれます。コーディングの際に、これら情報を使用できます。このパラメーターは
FCContext
型です。 - context パラメーターは次のように定義できます。
class Credentials:
def __init__(self, access_key_id, access_key_secret, security_token):
self.access_key_id = access_key_id
self.access_key_secret = access_key_secret
self.security_token = security_token
class ServiceMeta:
def __init__(self, service_name, log_project, log_store):
self.name = service_name
self.log_project = log_project
self.log_store = log_store
self.qualifier = qualifier
self.version_id = version_id
class FunctionMeta:
def __init__(self, name, handler, memory, timeout):
self.name = name
self.handler = handler
self.memory = memory
self.timeout = timeout
class FCContext:
def __init__(self, account_id, request_id, credentials, function_meta, service_meta, region):
self.request_id = request_id
self.credentials = credentials
self.function = function_meta
self.service = service_meta
self.region = region
self.account_id = account_id
前述の関数の主要パラメーターには次のものがあります。
request_id
: 呼び出しの一意の ID を示します。例外が発生した場合は、このパラメーターをメモして、トラブルシューティングを行うことができます。function
: 関数名、ハンドラ、関数メモリ、タイムアウト時間など、この関数に関する基本情報を示します。credentials
: Function Compute が、 サービスロールを想定して得られるキーを示します。これらのキーは、生成後 15 分で失効します。このパラメーターを使用して、 Object Storage Service (OSS) などの特定のサービスにアクセスできます。これにより、AccessKey が関数コードにハードコーディングされることを防ぎます。service
: 現在の関数が提供するサービスの詳細を指定します。たとえば、このパラメーターには、サービス名、および Log Service のログプロジェクトと Logstore、サービスのバージョンを示す修飾子、および versionId を含めることができます。region
: この関数が適用される cn-shanghai などのリージョンを示します。accountId
: Alibaba Cloud アカウントの ID を示します。
次のコードでは、OSS にファイルをアップロードするために Security Token Service (STS) が使用されています。
import json
import oss2
def my_handler(event, context):
evt = json.loads(event)
creds = context.credentials
# you must enter the security_token
auth = oss2.StsAuth(creds.access_key_id, creds.access_key_secret, creds.security_token)
bucket = oss2.Bucket(auth, evt['endpoint'], evt['bucket'])
bucket.put_object(evt['objectName'], evt['message'])
return 'success'
注意:キーを使用して OSS にアクセスできるようにするには、一時キーに、テンポラリトークンを使用する必要があります。
HTTP トリガーハンドラ
HTTP トリガーハンドラは、共通ハンドラとは異なります。つまり、HTTP トリガーが設定された関数のハンドラは、普通の関数のハンドラと異なります。
メソッド 1. ユーザーが関数を作成します。Function Compute は、 関数を呼び出して、リクエストを処理し、レスポンスを返します。
HELLO_WORLD = b"Hello world!\n"
def handler(environ, start_response):
context = environ['fc.context']
request_uri = environ['fc.request_uri']
for k, v in environ.items():
if k.startswith("HTTP_"):
# process custom request headers
pass
# get request_body
try:
request_body_size = int(environ.get('CONTENT_LENGTH', 0))
except (ValueError):
request_body_size = 0
request_body = environ['wsgi.input'].read(request_body_size)
# get request_method
request_method = environ['REQUEST_METHOD']
# get path info
path_info = environ['PATH_INFO']
# get server_protocol
server_protocol = environ['SERVER_PROTOCOL']
# get content_type
try:
content_type = environ['CONTENT_TYPE']
except (KeyError):
content_type = " "
# get query_string
try:
query_string = environ['QUERY_STRING']
except (KeyError):
query_string = " "
print 'request_body: {}'.format(request_body)
print 'method: {}\n path: {}\n query_string: {}\n server_protocol: {}\n'.format(request_method, path_info, query_string, server_protocol)
# do something here
status = '200 OK'
response_headers = [('Content-type', 'text/plain')]
start_response(status, response_headers)
# return value must be iterable
return [HELLO_WORLD]
メソッド 2. ユーザーは、呼び出し可能なクラスオブジェクトを作成します。Function Compute は、オブジェクトを呼び出し、リクエストを処理し、レスポンスを返します。
HELLO_WORLD = b"Hello world!\n"
class AppClass:
"""Produce the same output, but using a class
"""
def __init__(self, environ, start_response):
self.environ = environ
self.start = start_response
def __iter__(self):
status = '200 OK'
response_headers = [('Content-type', 'text/plain')]
self.start(status, response_headers)
yield HELLO_WORLD
def handler(environ, start_response):
return AppClass(environ, start_response)
Python ランタイム環境の関数シグネチャは、Python Web Server Gateway Interface (WSGI
) に準拠しています。
入力パラメーター
environ: このパラメーターは、すべてのクライアント関連情報を格納する Python 辞書を表します。詳細は、「Parameter environ」 をご参照ください。2 つのユーザー定義キー、
fc.context
とfc.request_uri
が Function Compute に追加されています。fc.context: 共通ハンドラの context パラメーターとして機能します。
fc.request_uri: リクエストの URL を示します。このパラメーターは string 型です。
注意:environ の
HTTP_Variables
フィールドは、リクエストヘッダーを含みます。たとえば、 リクエストヘッダーが'x-Custom-key':'value'
の場合、environ パラメーターは、environ['HTTP_X_CUSTOM_KEY']='value'
になります。WSGI によれば、リクエストヘッダー内のキーは、key = "HTTP_" + k.upper().replace("-","_")
として処理されます。start_response:start_response callable は、Function Compute のランタイム環境で提供されます。2 つの必須の位置パラメーターと 1つのオプションパラメーターがあります。詳細については、「the-start-response-callable」 をご参照ください。次の例では、3 つのパラメーターの名前は status、response_headers、exc_info としています。必要に応じて他の名前を使用することができます。
# Provided by Function Compute runtime.
# status: a string such as '200 OK' or '403 FORBIDDEN'
# return: must be a write(body_data) callable
def start_response(status, response_headers, exc_info=None):
...
- status: HTTP レスポンスステータスを示します。このパラメーターは string 型です。
response_headers: HTTP リクエストヘッダーを示します。(header_name, header_value) 形式のタプルを含むリストです。
exc_info (optional): サーバーがクライアントに返す必要のある情報を示します。
アプリケーションオブジェクトは、environ パラメーターに基づき、サービスロジックの実行を完了した後、結果をサーバーに返さなければなりません。HTTP レスポンスに、status、headers、および body パラメーターを含める必要があります。したがって、アプリケーションが body 値を返す前に、start_response() 関数を呼び出して、status と headers の値をサーバーに返さなければなりません。これにより、アプリケーションが body 値の送信を開始することがサーバーに通知されます。
Function Compute に WSGI ベースの Web フレームワークをデプロイする
前述の メソッド 2
の例では、Function Compute の Python ランタイム環境で、 Flask と Django を使用して、 WSGI ベースの Web フレームワーク上に構築されたプロジェクトを実行できることを示しています。以下は Flask
を例として使用しています。
from flask import Flask
from flask import request
from flask import make_response
app = Flask(__name__)
@app.route('/', methods=['GET', 'POST'])
def home():
resp = make_response('<h1>Home</h1>', 200)
return resp
@app.route('/signin', methods=['GET'])
def signin_form():
# service_name,function_name in action url need to be replaced
html = '''<form action="/2016-08-15/proxy/service_name/func_name/signin" method="post">
<p><input name="username"></p>
<p><input name="password" type="password"></p>
<p><button type="submit">Sign In</button></p>
</form>'''
resp = make_response(html, 200)
return resp
@app.route('/signin', methods=['POST'])
def signin():
if request.form['username'] == 'admin' and request.form['password'] == 'password':
html = '<h3>Hello, admin!</h3>'
else:
html = '<h3>Bad username or password.</h3>'
resp = make_response(html, 200)
return resp
@app.route('/signin2', methods=['GET'])
def signin2():
if request.args.get('username') == 'admin' and request.args.get('password') == 'password':
html = '<h3>Hello2, admin!</h3>'
else:
html = '<h3>Bad username or password.</h3>'
resp = make_response(html, 200)
return resp
def handler(environ, start_response):
# do something here
return app(environ, start_response)