前提:已经在电脑上安装了serverless框架
1. 修改项目的入口函数
由于采用了serverless,我们不再需要关心底层的服务器软件,因此我们需要改写腾讯云serverless的入口函数,使之传入的参数形式与django所需的参数相匹配。
在项目根目录下新建index.py:
只需要把倒数两行对应的适配你的项目名字就好了。
# -*- coding: utf-8 -*-
import os
import sys
import base64
from werkzeug.datastructures import Headers, MultiDict
from werkzeug.wrappers import Response
from werkzeug.urls import url_encode, url_unquote
from werkzeug.http import HTTP_STATUS_CODES
from werkzeug._compat import BytesIO, string_types, to_bytes, wsgi_encoding_dance
import RepairReportBackend.wsgi
TEXT_MIME_TYPES = [
"application/json",
"application/javascript",
"application/xml",
"application/vnd.api+json",
"image/svg+xml",
]
def all_casings(input_string):
if not input_string:
yield ""
else:
first = input_string[:1]
if first.lower() == first.upper():
for sub_casing in all_casings(input_string[1:]):
yield first + sub_casing
else:
for sub_casing in all_casings(input_string[1:]):
yield first.lower() + sub_casing
yield first.upper() + sub_casing
def split_headers(headers):
"""
If there are multiple occurrences of headers, create case-mutated variations
in order to pass them through APIGW. This is a hack that's currently
needed. See: https://github.com/logandk/serverless-wsgi/issues/11
Source: https://github.com/Miserlou/Zappa/blob/master/zappa/middleware.py
"""
new_headers = {}
for key in headers.keys():
values = headers.get_all(key)
if len(values) > 1:
for value, casing in zip(values, all_casings(key)):
new_headers[casing] = value
elif len(values) == 1:
new_headers[key] = values[0]
return new_headers
def group_headers(headers):
new_headers = {}
for key in headers.keys():
new_headers[key] = headers.get_all(key)
return new_headers
def encode_query_string(event):
multi = event.get(u"multiValueQueryStringParameters")
if multi:
return url_encode(MultiDict((i, j) for i in multi for j in multi[i]))
else:
return url_encode(event.get(u"queryString") or {})
def handle_request(application, event, context):
if u"multiValueHeaders" in event:
headers = Headers(event["multiValueHeaders"])
else:
headers = Headers(event["headers"])
strip_stage_path = os.environ.get("STRIP_STAGE_PATH", "").lower().strip() in [
"yes",
"y",
"true",
"t",
"1",
]
if u"apigw.tencentcs.com" in headers.get(u"Host", u"") and not strip_stage_path:
script_name = "/{}".format(event["requestContext"].get(u"stage", ""))
else:
script_name = ""
path_info = event["path"]
base_path = os.environ.get("API_GATEWAY_BASE_PATH")
if base_path:
script_name = "/" + base_path
if path_info.startswith(script_name):
path_info = path_info[len(script_name) :] or "/"
if u"body" in event:
body = event[u"body"] or ""
else:
body = ""
if event.get("isBase64Encoded", False):
body = base64.b64decode(body)
if isinstance(body, string_types):
body = to_bytes(body, charset="utf-8")
environ = {
"CONTENT_LENGTH": str(len(body)),
"CONTENT_TYPE": headers.get(u"Content-Type", ""),
"PATH_INFO": url_unquote(path_info),
"QUERY_STRING": encode_query_string(event),
"REMOTE_ADDR": event["requestContext"]
.get(u"identity", {})
.get(u"sourceIp", ""),
"REMOTE_USER": event["requestContext"]
.get(u"authorizer", {})
.get(u"principalId", ""),
"REQUEST_METHOD": event["httpMethod"],
"SCRIPT_NAME": script_name,
"SERVER_NAME": headers.get(u"Host", "lambda"),
"SERVER_PORT": headers.get(u"X-Forwarded-Port", "80"),
"SERVER_PROTOCOL": "HTTP/1.1",
"wsgi.errors": sys.stderr,
"wsgi.input": BytesIO(body),
"wsgi.multiprocess": False,
"wsgi.multithread": False,
"wsgi.run_once": False,
"wsgi.url_scheme": headers.get(u"X-Forwarded-Proto", "http"),
"wsgi.version": (1, 0),
"serverless.authorizer": event["requestContext"].get(u"authorizer"),
"serverless.event": event,
"serverless.context": context,
# TODO: Deprecate the following entries, as they do not comply with the WSGI
# spec. For custom variables, the spec says:
#
# Finally, the environ dictionary may also contain server-defined variables.
# These variables should be named using only lower-case letters, numbers, dots,
# and underscores, and should be prefixed with a name that is unique to the
# defining server or gateway.
"API_GATEWAY_AUTHORIZER": event["requestContext"].get(u"authorizer"),
"event": event,
"context": context,
}
for key, value in environ.items():
if isinstance(value, string_types):
environ[key] = wsgi_encoding_dance(value)
for key, value in headers.items():
key = "HTTP_" + key.upper().replace("-", "_")
if key not in ("HTTP_CONTENT_TYPE", "HTTP_CONTENT_LENGTH"):
environ[key] = value
response = Response.from_app(application, environ)
returndict = {u"statusCode": response.status_code}
if u"multiValueHeaders" in event:
returndict["multiValueHeaders"] = group_headers(response.headers)
else:
returndict["headers"] = split_headers(response.headers)
if event.get("requestContext").get("elb"):
# If the request comes from ALB we need to add a status description
returndict["statusDescription"] = u"%d %s" % (
response.status_code,
HTTP_STATUS_CODES[response.status_code],
)
if response.data:
mimetype = response.mimetype or "text/plain"
if (
mimetype.startswith("text/") or mimetype in TEXT_MIME_TYPES
) and not response.headers.get("Content-Encoding", ""):
returndict["body"] = response.get_data(as_text=True)
returndict["isBase64Encoded"] = False
else:
returndict["body"] = base64.b64encode(response.data).decode("utf-8")
returndict["isBase64Encoded"] = True
return returndict
from django.conf import settings
def main_handler(event, context):
# 因为我把所有的静态文件都存在了腾讯云cos,因此,在settings.py中,先把下面的STATIC_FC_URL设置为和static_url相同即可。
settings.STATIC_URL = event['host'] + '/' + settings.STATIC_FC_URL
return handle_request(myDjangoProject.wsgi.application, event, context)
2. 配置腾讯云COS
由于我把所有的静态文件都存在了腾讯云cos,因此需要先使用
python manage.py collectstatic
将所有的静态文件都收集了,然后把整个static文件夹传到腾讯云cos上面。
但是这个时候,有些js和css是无法正常调用的,那是因为腾讯云cos的安全策略的问题。需要在跨域访问CORS设置中,把你的来路域名添加进去,这样网页就能正常显示了。
3. 安装项目依赖
在项目根目录下创建requirements.txt,将 Python 所需要的依赖安装到项目目录
pip install -r requirements.txt -t ./
4. 配置 yml 文件
在项目根目录下,新建 serverless.yml
文件,并将下列配置模版粘贴到文件中,实现基本的项目配置。
#serverless.yml
component: django
name: djangoDemo
app: appDemo
stage: dev
inputs:
region: ap-guangzhou
djangoProjectName: mydjangocomponent
src: ./src
functionConf:
timeout: 10
memorySize: 256
environment:
variables:
TEST: vale
apigatewayConf:
protocols:
- https
environment: release
5. 应用部署
通过 sls deploy
命令进行部署,并可以添加 –debug 参数查看部署过程中的信息。
sls deploy --debug
部署完成后,通过访问输出的 API 网关链接,完成对应用的访问。
转载请注明来源:https://www.longjin666.top/?p=921
欢迎关注我的公众号“灯珑”,让我们一起了解更多的事物~