我希望使用python从单个GCP云功能提供多个路由。虽然GCP功能实际上在内部使用了Flask,但我似乎无法弄清楚如何使用Flask路由系统通过单个云功能为多个路由提供服务。
我当时在做一个很小的项目,所以我写了一个自己的快速路由器,效果很好。现在,我更多地使用了GCP功能,我想弄清楚如何使用Flask路由器,或者在我的手动版本和开放源代码上投入更多的时间,尽管当它看起来非常实用时似乎显得多余了。烧瓶路由的紧密副本,因此如果不存在此功能,最好将其直接添加到Flask中。
有人在这个问题上有经验吗?我猜想我缺少一个简单的函数来使用它隐藏在Flask的某个地方,但是如果不是这样,这似乎是一个很大的/常见的问题,尽管我猜GCP Functions python是beta版是有原因的?
编辑: 如果可能的话,我想使用Flask的简化版本的示例:
router = MyRouter()
@router.add('some/path', RouteMethod.GET)
def handle_this(req):
...
@router.add('some/other/path', RouteMethod.POST)
def handle_that(req):
...
# main entry point for the cloud function
def main(request):
return router.handle(request)
答案 0 :(得分:1)
多亏了Guillaume Blaquiere的article的启发和一些调整,我有一种方法可以使我使用ngrok生成用于本地测试和开发Google Cloud Functions的公共URL。
我有两个关键文件app.py和main.py。
我正在使用VS-Code,现在可以按F5打开app.py,选择“调试当前文件”。现在,我可以在函数main.py中设置断点了。我安装了“ REST客户端”扩展程序,它使我能够配置GET和POST调用,这些调用可以针对本地URL和ngrok URL运行。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#app.py
import os
from flask import Flask, request, Response
from main import callback
app = Flask(__name__)
@app.route('/', methods=['GET', 'POST'])
def test_function():
return callback(request)
def start_ngrok():
from pyngrok import ngrok
ngrok_tunnel = ngrok.connect(5000)
print(' * Tunnel URL:', ngrok_tunnel.public_url)
if __name__ == '__main__':
if os.environ.get('WERKZEUG_RUN_MAIN') != 'true':
start_ngrok()
app.run(debug=True)
#!/usr/bin/env python3
# This file main.py can be run as a Google Cloud function and deployed with:
# gcloud functions deploy callback --runtime python38 --trigger-http --allow-unauthenticated
from flask import Response
import datetime
now = datetime.datetime.now()
def callback(request):
if request.method == 'POST': # Block is only for POST request
print(request.json)
return Response(status=200)
return Response(f'''
<!doctype html><title>Hello from webhook</title>
<body><h1>Hello! </h1><p>{now:%Y-%m-%d %H:%M}</p>
</body></html>
''', status=200)
答案 1 :(得分:1)
@rabelenda 的简化版也适用于我:
def main(request):
with app.request_context(request.environ):
try:
rv = app.preprocess_request()
if rv is None:
rv = app.dispatch_request()
except Exception as e:
rv = app.handle_user_exception(e)
response = app.make_response(rv)
return app.process_response(response)
答案 2 :(得分:0)
以下解决方案对我有用:
import flask
import werkzeug.datastructures
app = flask.Flask(__name__)
@app.route('some/path')
def handle_this(req):
...
@app.route('some/other/path', methods=['POST'])
def handle_that(req):
...
def main(request):
with app.app_context():
headers = werkzeug.datastructures.Headers()
for key, value in request.headers.items():
headers.add(key, value)
with app.test_request_context(method=request.method, base_url=request.base_url, path=request.path, query_string=request.query_string, headers=headers, data=request.data):
try:
rv = app.preprocess_request()
if rv is None:
rv = app.dispatch_request()
except Exception as e:
rv = app.handle_user_exception(e)
response = app.make_response(rv)
return app.process_response(response)
答案 3 :(得分:0)
感谢@rabelenda的上述回答启发了我的答案,它只是调整了data / json参数,并支持对InternalServerError未处理的异常处理程序的支持:
import werkzeug.datastructures
def process_request_in_app(request, app):
# source: https://stackoverflow.com/a/55576232/1237919
with app.app_context():
headers = werkzeug.datastructures.Headers()
for key, value in request.headers.items():
headers.add(key, value)
data = None if request.is_json else (request.form or request.data or None)
with app.test_request_context(method=request.method,
base_url=request.base_url,
path=request.path,
query_string=request.query_string,
headers=headers,
data=data,
json=request.json if request.is_json else None):
try:
rv = app.preprocess_request()
if rv is None:
rv = app.dispatch_request()
except Exception as e:
try:
rv = app.handle_user_exception(e)
except Exception as e:
# Fallback to unhandled exception handler for InternalServerError.
rv = app.handle_exception(e)
response = app.make_response(rv)
return app.process_response(response)
答案 4 :(得分:0)
Martin 的解决方案对我有用,直到我尝试在其中一条路线中调用 request.get_json()
。最终结果是响应在较低级别被阻塞,因为数据流已经被消耗。
我在 Google Cloud Run 中使用 functions_framework
寻找解决方案时遇到了这个问题。它已经设置了一个 app
,您可以通过从 Flask 导入 current_app
来获得它。
from flask import current_app
app = current_app
我相信 functions_framework
被 Google Cloud Functions 使用,所以它也应该在那里工作。