网站托管是云引擎的一个子模块,允许你用 Python 开发一个 Web 程序,提供云函数和 Hook,还可以提供静态文件的托管和自定义的路由、绑定你自己的域名。你可以用它为你的移动应用提供一个介绍和下载页、开发一个管理员控制台或完整的网站,或者运行一些必须在服务器端运行的自定义逻辑。
如果你还不知道如何创建云引擎项目,本地调试并部署到云端,可以先阅读一下 云引擎快速入门。其他相关文档包括:
这篇文档以 Python 为例,但云引擎还支持其他多种语言,你可以选择自己熟悉的技术栈进行开发:
我们为云引擎支持的各种语言准备了示例项目,建议从示例项目着手开始开发。
要理解如何从示例项目开始开发云引擎项目,本地调试,部署到云端,请先阅读 云引擎快速入门。
参照示例项目,你的项目需要遵循一定格式才会被云引擎识别并运行。
使用 WSGI 规范来运行项目,项目根目录下必须有 wsgi.py 与 requirements.txt 文件,可选文件 .python-version、runtime.txt。云引擎运行时会首先加载 wsgi.py 这个模块,并将此模块的全局变量 application 作为 WSGI 函数进行调用。因此请保证 wsgi.py 文件中包含一个 application 的全局变量/函数/类,并且符合 WSGI 规范。
wsgi.py
requirements.txt
.python-version
runtime.txt
application
更多关于 WSGI 函数 的内容,请参考 PEP333。
requirements.txt 中填写项目依赖的第三方模块,每行一个,如:
# 井号至行尾为注释 leancloud>=2.6.0,<3.0.0 Flask>=1.0.0 # 可以指定版本号/范围 git+https://github.com/foo/bar.git@master#egg=bar # 可以使用 Git/SVN 等版本管理工具的远程地址
详细格式请参考 pip 19.0.1 Documentation > User Guide > Requirements Files。
应用部署到云引擎之后,会自动按照 requirements.txt 中的内容进行依赖安装。在本地运行和调试项目的时候,可以在项目目录下使用如下命令安装依赖:
pip install -r requirements.txt
另外当你部署应用的时候,建议将依赖的包的版本都按照 foo==1.0.0 这种格式来明确指定版本号(或版本的范围),防止因为依赖的模块升级且不再兼容老的 API 时,再次部署会导致应用运行失败。
foo==1.0.0
你可以选择运行代码的 Python 版本,选择方法与 pyenv 相同,即在项目根目录的 .python-version 中写入需要的 Python 版本即可,比如 3.6.1。这样将代码部署到云引擎之后,系统会自动选择对应的 Python 版本。
pyenv
3.6.1
如果在本地开发时已使用了 pyenv,pyenv 也会根据此文件来自动使用对应的 Python 运行项目。我们建议本地开发使用 pyenv,以保证本地环境与线上相同。pyenv 的安装方法请参考 pyenv 的 GitHub 仓库。
目前仅支持 CPython 版本,暂时不支持 PyPy、Jython、IronPython 等其他 Python 实现。另外建议尽量使用 3.5 或以上版本的 Python 进行开发,如果仍然在使用 Python 2 ,请使用 Python 2.7 进行开发。
如前所述,只要兼容 Python WSGI 规范的框架都可以在云引擎运行。目前比较流行的 Python Web 框架对此都有支持,比如 Flask、Django、Tornado。我们提供了 Flask 和 Django 两个框架的示例项目作为参考,你也可以直接把它们当作一个应用项目的初始化模版:
在云引擎中你可以使用 LeanCloud 提供的 数据存储 作为应用的后端数据库,以及使用其他 LeanCloud 提供的功能。LeanCloud Python SDK 可以让你更加方便地使用这些功能。
将 leancloud 添加到 requirements.txt 中,部署到线上即可自动安装此依赖。在本地运行和调试项目的时候,可以在项目目录下使用如下命令进行依赖安装:
leancloud
LeanCloud Python SDK 目前最新版本已经升级到了 2.0.0,与之前的 1.x 版本相比有了一些不兼容的改动,主要是移除了一些已经废弃的方法,详情参考 SDK 发布页面。
不过目前云引擎上有一部分使用者,没有在 requirements.txt 中指定依赖的 Python SDK 版本,因此我们暂时没有将 2.x 分支的代码发布到 pypi 的 leancloud-sdk 这个包下,防止对这部分使用者正在运行的代码造成影响。因此目前如果需要使用 2.x 版本的 SDK 的话,请使用 leancloud 这个包名。
leancloud-sdk
因为 wsgi.py 是项目最先被执行的文件,推荐在此文件进行 LeanCloud Python SDK 的初始化工作:
import os import leancloud APP_ID = os.environ['LEANCLOUD_APP_ID'] # 从 LEANCLOUD_APP_ID 这个环境变量中获取应用 App ID 的值 APP_KEY = os.environ['LEANCLOUD_APP_KEY'] # 从 LEANCLOUD_APP_KEY 这个环境变量中获取应用 App Key 的值 MASTER_KEY = os.environ['LEANCLOUD_APP_MASTER_KEY'] # 从 LEANCLOUD_APP_MASTER_KEY 这个环境变量中获取应用 Master Key 的值 leancloud.init(APP_ID, app_key=APP_KEY, master_key=MASTER_KEY) # 如果需要使用 Master Key 权限访问 LeanCloud 服务,请将这里设置为 True leancloud.use_master_key(False)
接下来就可以在项目的其他部分中使用 LeanCloud Python SDK 提供的功能了。更多用法请参考 数据存储开发指南 · Python。
你的应用在启动时,云引擎的管理程序会每秒去检查你的应用是否启动成功,如果 30 秒 仍未启动成功,即认为启动失败;在之后应用正常运行的过程中,也会有定期的「健康监测」,以确保你的应用正常运行,如果健康监测失败,云引擎管理程序会自动重启你的应用。
健康检查的 URL 包括你的应用首页(/)和 Python SDK 负责处理的 /__engine/1/ping,只要 两者之一 返回了 HTTP 200 的响应,就视作成功。因此请确保你的程序使用了 Python SDK,或你的应用 首页能够正常地返回 HTTP 200 响应。除此之外,为了支持云引擎的云函数和 Hook 功能,管理程序会使用 /1.1/functions/_ops/metadatas 这个 URL 和 Python SDK 交互,请确保将这个 URL 交给 Python SDK 处理,或 返回一个 HTTP 404 表示不使用云函数和 Hook 相关的功能。
/
/__engine/1/ping
200
/1.1/functions/_ops/metadatas
404
关于如何加载 Python 数据存储 SDK,见前一小节 使用数据存储服务。
Python SDK 提供了一个 leancloud.engine.CookieSessionMiddleware 的 WSGI 中间件,使用 Cookie 来维护用户(leancloud.User)的登录状态。要使用这个中间件,可以在 wsgi.py 中将:
leancloud.engine.CookieSessionMiddleware
leancloud.User
application = engine
替换为:
application = leancloud.engine.CookieSessionMiddleware(engine, secret=YOUR_APP_SECRET)
你需要传入一个 secret 的参数用于签名 Cookie(必须提供),这个中间件会将 AV.User 的登录状态信息记录到 Cookie 中,用户下次访问时自动检查用户是否已经登录,如果已经登录,可以通过 leancloud.User.get_current() 获取当前登录用户。
secret
AV.User
leancloud.User.get_current()
leancloud.engine.CookieSessionMiddleware 初始化时支持的非必须选项包括:
leancloud:session
list
False
session_token
fetch()
True
你可以使用任意 Python 的模块来发送 HTTP 请求,比如内置的 urllib。不过我们推荐 requests 这个第三方模块。 LeanCloud Python SDK 就使用 requests 调用 LeanCloud 的 REST API 接口。 因此,如果你的项目已经依赖了 LeanCloud Python SDK,那么你无需在 requirements.txt 中另外指定 requests 这个依赖。 否则,你可以在 requirements.txt 中新增一行 requests,然后在此目录重新执行 pip install -r requirements.txt 安装 requests 模块。
urllib
requests
import requests response = requests.post('http://www.example.com/create_post', json={ 'title': 'Some Amazing Title', 'body': 'Some awesome content.', }) print(response.json())
如果你想获取客户端的 IP,可以直接从用户请求的 HTTP 头的 x-real-ip 字段获取,示例代码如下:
x-real-ip
Flask:
from flask import Flask from flask import request app = Flask(__name__) @app.route('/') def index(): print(request.headers['x-real-ip']) return 'ok'
Django:
根据 Django 的官方文档,第三方定义的 HTTP Header 会加上 HTTP_ 的前缀,并且 - 会被替换成 _,所以要通过 HTTP_X_REAL_IP 来访问。
HTTP_
-
_
HTTP_X_REAL_IP
def index(request): print(request.META['HTTP_X_REAL_IP']) return render(request, 'index.html', {})
其他框架请参考对应文档。
注意,国内节点的云引擎应用,如果启用了边缘节点加速功能,那么由于边缘节点的限制,无法获取客户端 IP。
托管在 LeanEngine 的网站项目可以直接使用内置的 LeanCloud Python SDK 的 API 文件相关的接口直接处理文件的上传。
假设前端 HTML 代码如下:
<form enctype="multipart/form-data" method="post" action="/upload"> <input type="file" name="iconImage"> <input type="submit" name="submit" value="submit"> </form>
接下来定义文件上传的处理函数,构建一个 Form 对象,并将 req 作为参数进行解析,会将请求中的文件保存到临时文件目录,并构造 files 对象:
Form
req
files
# app 是一个 Flask 实例 @app.route('/upload', methods=['POST']) def upload(): upload_file = request.files['iconImage'] f = leancloud.File(upload_file.filename, data=upload_file.stream) print(f.url) return '上传成功!'
其他 Web 框架,请参考对应文档。
推荐使用 Web 框架自带的 session 组件。
session
如果你的云引擎应用使用 Cookie 作为鉴权方式的话(例如使用 SDK 的 CookieSession中间件),那么就有受到 CSRF 攻击的风险,将会允许其他站点伪造带有正确 Cookie 的恶意请求。
CookieSession
业界通常使用 CSRF Token 来防御 CSRF 攻击,你需要传递给客户端一个随机字符串(即 CSRF Token,可通过 Cookie 传递),客户端在每个有副作用的请求中都要将 CSRF 包含在请求正文或 Header 中,服务器端需要校验这个 CSRF Token 是否正确。
LeanCache 是 LeanCloud 为大流量站点提供的一项缓存服务。
要使用 LeanCache,首先将 redis 依赖添加到 requirements.txt 中:
redis
Flask>=1.0.0 leancloud>=2.6.0,<3.0.0 … redis>=2.10.5,<3.0.0
然后可以使用下列代码获取 Redis 连接:
import os import redis r = redis.from_url(os.environ.get("REDIS_URL_<instance_name>"))
关于 LeanCache 的更多使用方法请看 LeanCache 使用指南。
为了安全性,我们可能会为网站加上 HTTPS 加密传输。我们的 LeanEngine 支持网站托管,同样会有这样的需求。因此我们在 LeanEngine 中提供了一个 middleware 来强制网站通过 HTTPS 访问,你只要这样:
import leancloud application = get_your_wsgi_func() application = leancloud.HttpsRedirectMiddleware(application)
部署并发布到生产环境之后,访问你的 LeanEngine 网站都会强制通过 HTTPS 访问。
在你的项目根目录运行:
lean deploy
使用命令行工具可以非常方便地部署、发布应用,查看应用状态,查看日志,甚至支持多应用部署。具体使用请参考 命令行工具指南。
云引擎实现了一个缓存机制来加快构建的速度,所谓构建就是指你的应用在云引擎上安装依赖的过程,在每次构建时,如果依赖没有新增或者删减,那么就直接使用上次安装的依赖,只将新的应用代码替换上去。
依赖缓存也会因为很多原因失效,因此不保证每次构建都可以利用上缓存。
如果你遇到了与依赖安装有关的问题,可以在控制台部署时勾选「下载最新依赖」,或通过命令行工具部署时添加 --no-cache 选项。
--no-cache
lean deploy --no-cache
除此之外,还可以使用 git 仓库部署。你需要将项目提交到一个 git 仓库,我们并不提供源码的版本管理功能,而是借助于 git 这个优秀的分布式版本管理工具。我们推荐你使用 GitHub、Coding 或者 码云 这样第三方的源码托管网站,也可以使用你自己搭建的 git 仓库(比如 GitLab)。
你需要先在这些平台上创建一个项目(如果已有代码,请不需要选择「Initialize this repository with a README」),在网站的个人设置中填写本地机器的 SSH 公钥(以 GitHub 为例,在 Settings > SSH and GPG keys 中点击 New SSH key),然后在项目目录执行:
git remote add origin git@github.com:<username>/<repoName>.git git push -u origin master
然后到云引擎的设置界面填写你的 Git 仓库地址,如果是公开仓库建议填写 HTTPS 地址,例如 https://github.com/<username>/<repoName>.git。
https://github.com/<username>/<repoName>.git
如果是私有仓库需要填写 SSH 地址(git@github.com:<username>/<repoName>.git),还需要你将云引擎分配给你的公钥填写到第三方托管平台的 Deploy keys 中,以 GitHub 为例,在项目的 Settings > Deploy keys 中点击 Add deploy key。
git@github.com:<username>/<repoName>.git
设置好之后,今后需要部署代码时就可以在云引擎的部署界面直接点击「部署」了,默认会部署 master 分支的代码,你也可以在部署时填写分支、标签或具体的 Commit。 如果仓库使用了 submodule,云引擎也会自动拉取 submodule。
master
如果希望 push 到项目的 Git 仓库的特定分支后自动触发云引擎部署,可以在应用的 控制台 > 云引擎 > 部署 > git 部署 > 自动部署 查看 deploy token 和 webhook 地址。 控制台显示的 deploy token 可以用来构造 HTTP 请求触发部署。 在控制台填写项目仓库的分支名称,并选择云引擎的运行环境后,控制台会生成相应的 webhook 地址。 该地址收到任意 POST 请求后,会部署指定分支的代码到指定的运行环境。
例如,在 GitHub 代码仓库的 Settings > Webhooks > Payload URL 填写生成的 webhook 后(其他选项均使用默认值,不用修改),下次 push 到项目仓库的 任意 分支,云引擎会自动根据 指定 分支更新代码,重新部署。之所以 push 到任意分支都会触发重新部署,是因为 GitHub 的 webhook 触发事件设置粒度较粗,不能指定仅在 push 到特定分支时触发 webhook。另一方面,云引擎也没有适配具体的托管平台,不会根据 GitHub 提交的 POST 内容中的分支信息决定是否重新部署。 不过,你可以使用 GitHub Action 更精细地控制部署时机,具体可以参考控制台显示的示例。
默认情况,云引擎只有一个「生产环境」。在生产环境中有一个「体验实例」来运行应用。
当生产环境的体验实例升级到「标准实例」后会有一个额外的「预备环境」。两个环境所访问的都是同样的数据,你可以用预备环境测试你的云引擎代码,每次修改先部署到预备环境,测试通过后再发布到生产环境;如果你希望有一个独立数据源的测试环境,建议单独创建一个应用。
在云引擎托管的网站需要绑定域名才能访问。 以 stg- 开头的域名会自动绑定到预备环境。
stg-
如果访问云引擎遇到「Application not Found」的错误,通常是因为对应的环境还没有部署代码。例如应用可能没有预备环境,或应用尚未发布代码到生产环境
有些时候你可能需要知道当前云引擎运行在什么环境(开发环境、预备环境或生产环境),从而做不同的处理:
import os env = os.environ.get('LEANCLOUD_APP_ENV') if env == 'development': # 当前环境为「开发环境」,是由命令行工具启动的 do_some_thing() elif env == 'production': # 当前环境为「生产环境」,是线上正式运行的环境 do_some_thing() elif env == 'stage': # 当前环境为「预备环境」 do_some_thing()
你还可以在 SDK 中指定客户端将请求所发往的环境:
[AVCloud setProductionMode:YES]; // 生产环境(默认) [AVCloud setProductionMode:NO]; // 预备环境
// 默认为生产环境 // 预备环境 do { let environment: LCApplication.Environment = [.cloudEngineDevelopment] let configuration = LCApplication.Configuration(environment: environment) try LCApplication.default.set( id: {{appid}}, key: {{appkey}}, // 请将 xxx.example.com 替换为你的应用绑定的自定义 API 域名 serverURL: "https://xxx.example.com", configuration: configuration) } catch { print(error) }
AV.setProduction(true); // 生产环境(默认) AV.setProduction(false); // 预备环境
leancloud.use_production(True) # 生产环境(默认) leancloud.use_production(False) # 预备环境 # 需要在 SDK 初始化语句 `leancloud.init` 之前调用
LeanClient::useProduction(true); // 生产环境(默认) LeanClient::useProduction(false); // 预备环境
AVCloud.setProductionMode(true); // 生产环境(默认) AVCloud.setProductionMode(false); // 预备环境
在云引擎的线上环境中,你可以通过 leanengine.yaml 文件的 systemDependencies 部分来自定义系统级依赖:
leanengine.yaml
systemDependencies
systemDependencies: - imagemagick
目前支持的选项包括:
ffmpeg
imagemagick
fonts-wqy
phantomjs
chrome-headless
fonts-noto
puppeter
puppeteer.launch
{executablePath: '/usr/bin/google-chrome', args: ['--no-sandbox', '--disable-setuid-sandbox']}
node-canvas
python-talib
注意添加系统依赖将会拖慢部署速度,因此请不要添加未用到的依赖。
云引擎平台默认提供下列环境变量供应用使用:
LEANCLOUD_APP_ID
LEANCLOUD_APP_KEY
LEANCLOUD_APP_MASTER_KEY
LEANCLOUD_APP_ENV
development
stage
production
LEANCLOUD_APP_PORT
LEANCLOUD_API_SERVER
https://api.leancloud.cn
LEANCLOUD_APP_GROUP
LEANCLOUD_REGION
CN
US
LEANCLOUD_VERSION_TAG
旧版云引擎使用的以 LC_ 开头的环境变量(如 LC_APP_ID)已经被弃用。为了保证代码兼容性,LC_ 变量在一段时间内依然有效,但未来可能会完全失效。为了避免报错,建议使用 LEANCLOUD_ 变量来替换。
LC_
LC_APP_ID
LEANCLOUD_
你也可以在 控制台 > 云引擎 > 设置 > 自定义环境变量 页面中添加自定义的环境变量。其中名字必须是字母、数字、下划线且以字母开头,值必须是字符串,修改环境变量后会在下一次部署时生效。
按照一般的实践,可以将一些配置项存储在环境变量中,这样可以在不修改代码的情况下,修改环境变量并重新部署,来改变程序的行为;或者可以将一些第三方服务的 Secret Key 存储在环境变量中,避免这些密钥直接出现在代码中。
# 在云引擎 Python 环境中使用自定义的环境变量 import os MY_CUSTOM_VARIABLE = os.environ.get('MY_CUSTOM_VARIABLE') print(MY_CUSTOM_VARIABLE)
云引擎运行环境默认提供的环境变量无法被自定义环境变量覆盖(覆盖无效)。
默认情况下,应用在运行阶段才能够读取到内置环境变量和自定义环境变量。 如果希望在安装依赖或编译阶段就能读取到这些环境变量,需要在 leanengine.yaml 里设置:
exposeEnvironmentsOnBuild: true
在云引擎上,用户的请求会先经过负载均衡组件,然后到达你的应用。 负载均衡组件会处理 HTTPS 加密、对响应进行压缩等一般性工作,因此你不必在你的应用中添加 HTTPS 或 gzip 相关的功能。 也因为 HTTPS 加密是在负载均衡层面处理的,所以通常部署在云引擎上的 web 框架获取的请求 URL 总是使用 HTTP 协议,建议通过 X-Forwarded-Proto HTTP 头来判断原请求是通过 HTTP 还是 HTTPS 访问的。
X-Forwarded-Proto
负载均衡同时限制了请求不能超过 100 MB(包括直接上传文件到云引擎)、请求处理不得超过 60 秒,WebSocket 60 秒无数据会被断开连接。
国内节点未绑定独立 IP 的云引擎默认为纯静态站点优化。请求会先经过边缘节点,再视缓存命中情况回源到负载均衡组件,最后到达你的应用。 边缘节点额外限制了请求不能超过 60 MB、请求处理不得超过 10 秒,另外边缘节点不支持 WebSocket 请求和 HTTP PATCH 方法,也不支持获取客户端 IP。 因此,如果您在国内节点云引擎托管动态网站,我们建议您绑定独立 IP,使用独立入口,不经过边缘节点,自然也就没有上述限制。
你可以向 /home/leanengine 或 /tmp 目录写入临时文件,最多不能超过 1 GB。
/home/leanengine
/tmp
云引擎每次部署都会产生一个新的容器,即使不部署系统偶尔也会进行一些自动调度,这意味着你 不能将本地文件系统当作持久的存储,只能用作临时存储。
如果你写入的文件体积较大,建议在使用后自动删除他们,否则如果占用磁盘空间超过 1 GB,继续写入文件可能会收到类似 Disk quota exceeded 的错误,这种情况下你可以重新部署一下,这样文件就会被清空了。
Disk quota exceeded
在 控制台 > 云引擎 > 日志 中可以查看云引擎的部署和运行日志,还可以通过日志级别进行筛选。
你还可以 通过命令行工具来导出 最近七天的日志到本地文件,方便进行进一步的分析和统计。
应用的日志可以直接输出到「标准输出」或者「标准错误」,这些信息会分别对应日志的 info 和 error 级别,比如下列代码会在 info 级别输出 'Hello!':
info
error
'Hello!'
Python 2:
import sys print 'Hello!' # info print >> sys.stderr, 'An error occurred!' # error
Python 3:
import sys print('Hello!') # info print('An error occurred!', file=sys.stderr) # error
日志单行最大 4096 个字符,多余部分会被丢弃;日志输出频率大于 600 行/分钟,多余的部分会被丢弃。
云引擎的访问日志(Access Log)可在 控制台 > 云引擎 > 访问日志 中导出,通过控制台下载经过打包的日志。
在云引擎的中国区系统默认使用北京时间(Asia/Shanghai),美国区默认使用 UTC 时间。
Asia/Shanghai
如果开发者希望在第三方服务平台(如微信开放平台)上配置 IP 白名单而需要获取云引擎的入口或出口 IP 地址,请进入 控制台 > 云引擎 > 设置 > 出入口 IP 来自助查询。
我们会尽可能减少出入口 IP 的变化频率,但 IP 突然变换的可能性仍然存在。因此在遇到与出入口 IP 相关的问题,我们建议先进入控制台来核实一下 IP 列表是否有变化。
根据法律法规和有关部门的要求,使用云引擎网站托管服务需要 绑定自有域名。
网站托管开发指南 · Python
网站托管是云引擎的一个子模块,允许你用 Python 开发一个 Web 程序,提供云函数和 Hook,还可以提供静态文件的托管和自定义的路由、绑定你自己的域名。你可以用它为你的移动应用提供一个介绍和下载页、开发一个管理员控制台或完整的网站,或者运行一些必须在服务器端运行的自定义逻辑。
如果你还不知道如何创建云引擎项目,本地调试并部署到云端,可以先阅读一下 云引擎快速入门。其他相关文档包括:
这篇文档以 Python 为例,但云引擎还支持其他多种语言,你可以选择自己熟悉的技术栈进行开发:
从示例项目开始
我们为云引擎支持的各种语言准备了示例项目,建议从示例项目着手开始开发。
要理解如何从示例项目开始开发云引擎项目,本地调试,部署到云端,请先阅读 云引擎快速入门。
项目骨架
参照示例项目,你的项目需要遵循一定格式才会被云引擎识别并运行。
使用 WSGI 规范来运行项目,项目根目录下必须有
wsgi.py
与requirements.txt
文件,可选文件.python-version
、runtime.txt
。云引擎运行时会首先加载wsgi.py
这个模块,并将此模块的全局变量application
作为 WSGI 函数进行调用。因此请保证wsgi.py
文件中包含一个application
的全局变量/函数/类,并且符合 WSGI 规范。更多关于 WSGI 函数 的内容,请参考 PEP333。
添加第三方依赖模块
requirements.txt
中填写项目依赖的第三方模块,每行一个,如:详细格式请参考 pip 19.0.1 Documentation > User Guide > Requirements Files。
应用部署到云引擎之后,会自动按照
requirements.txt
中的内容进行依赖安装。在本地运行和调试项目的时候,可以在项目目录下使用如下命令安装依赖:另外当你部署应用的时候,建议将依赖的包的版本都按照
foo==1.0.0
这种格式来明确指定版本号(或版本的范围),防止因为依赖的模块升级且不再兼容老的 API 时,再次部署会导致应用运行失败。指定 Python 版本
你可以选择运行代码的 Python 版本,选择方法与
pyenv
相同,即在项目根目录的.python-version
中写入需要的 Python 版本即可,比如3.6.1
。这样将代码部署到云引擎之后,系统会自动选择对应的 Python 版本。如果在本地开发时已使用了
pyenv
,pyenv
也会根据此文件来自动使用对应的 Python 运行项目。我们建议本地开发使用pyenv
,以保证本地环境与线上相同。pyenv
的安装方法请参考pyenv
的 GitHub 仓库。目前仅支持 CPython 版本,暂时不支持 PyPy、Jython、IronPython 等其他 Python 实现。另外建议尽量使用 3.5 或以上版本的 Python 进行开发,如果仍然在使用 Python 2 ,请使用 Python 2.7 进行开发。
如前所述,只要兼容 Python WSGI 规范的框架都可以在云引擎运行。目前比较流行的 Python Web 框架对此都有支持,比如 Flask、Django、Tornado。我们提供了 Flask 和 Django 两个框架的示例项目作为参考,你也可以直接把它们当作一个应用项目的初始化模版:
使用数据存储服务
在云引擎中你可以使用 LeanCloud 提供的 数据存储 作为应用的后端数据库,以及使用其他 LeanCloud 提供的功能。LeanCloud Python SDK 可以让你更加方便地使用这些功能。
安装
将
leancloud
添加到requirements.txt
中,部署到线上即可自动安装此依赖。在本地运行和调试项目的时候,可以在项目目录下使用如下命令进行依赖安装:升级到 2.x
LeanCloud Python SDK 目前最新版本已经升级到了 2.0.0,与之前的 1.x 版本相比有了一些不兼容的改动,主要是移除了一些已经废弃的方法,详情参考 SDK 发布页面。
不过目前云引擎上有一部分使用者,没有在
requirements.txt
中指定依赖的 Python SDK 版本,因此我们暂时没有将 2.x 分支的代码发布到 pypi 的leancloud-sdk
这个包下,防止对这部分使用者正在运行的代码造成影响。因此目前如果需要使用 2.x 版本的 SDK 的话,请使用leancloud
这个包名。初始化
因为
wsgi.py
是项目最先被执行的文件,推荐在此文件进行 LeanCloud Python SDK 的初始化工作:接下来就可以在项目的其他部分中使用 LeanCloud Python SDK 提供的功能了。更多用法请参考 数据存储开发指南 · Python。
健康监测
你的应用在启动时,云引擎的管理程序会每秒去检查你的应用是否启动成功,如果 30 秒 仍未启动成功,即认为启动失败;在之后应用正常运行的过程中,也会有定期的「健康监测」,以确保你的应用正常运行,如果健康监测失败,云引擎管理程序会自动重启你的应用。
健康检查的 URL 包括你的应用首页(
/
)和 Python SDK 负责处理的/__engine/1/ping
,只要 两者之一 返回了 HTTP200
的响应,就视作成功。因此请确保你的程序使用了 Python SDK,或你的应用 首页能够正常地返回 HTTP200
响应。除此之外,为了支持云引擎的云函数和 Hook 功能,管理程序会使用/1.1/functions/_ops/metadatas
这个 URL 和 Python SDK 交互,请确保将这个 URL 交给 Python SDK 处理,或 返回一个 HTTP404
表示不使用云函数和 Hook 相关的功能。关于如何加载 Python 数据存储 SDK,见前一小节 使用数据存储服务。
用户状态管理
Python SDK 提供了一个
leancloud.engine.CookieSessionMiddleware
的 WSGI 中间件,使用 Cookie 来维护用户(leancloud.User
)的登录状态。要使用这个中间件,可以在wsgi.py
中将:替换为:
你需要传入一个
secret
的参数用于签名 Cookie(必须提供),这个中间件会将AV.User
的登录状态信息记录到 Cookie 中,用户下次访问时自动检查用户是否已经登录,如果已经登录,可以通过leancloud.User.get_current()
获取当前登录用户。leancloud.engine.CookieSessionMiddleware
初始化时支持的非必须选项包括:leancloud:session
。list
。False
的话,leancloud.User.get_current()
获取到的用户数据上除了session_token
之外没有任何其他数据,需要自己调用fetch()
来获取。为True
的话,会自动在用户对象上调用fetch()
,这样将会产生一次数据存储的 API 调用。默认为False
。实现常见的网站功能
发送 HTTP 请求
你可以使用任意 Python 的模块来发送 HTTP 请求,比如内置的
urllib
。不过我们推荐requests
这个第三方模块。 LeanCloud Python SDK 就使用 requests 调用 LeanCloud 的 REST API 接口。 因此,如果你的项目已经依赖了 LeanCloud Python SDK,那么你无需在requirements.txt
中另外指定 requests 这个依赖。 否则,你可以在requirements.txt
中新增一行requests
,然后在此目录重新执行pip install -r requirements.txt
安装 requests 模块。获取客户端 IP
如果你想获取客户端的 IP,可以直接从用户请求的 HTTP 头的
x-real-ip
字段获取,示例代码如下:Flask:
Django:
根据 Django 的官方文档,第三方定义的 HTTP Header 会加上
HTTP_
的前缀,并且-
会被替换成_
,所以要通过HTTP_X_REAL_IP
来访问。其他框架请参考对应文档。
注意,国内节点的云引擎应用,如果启用了边缘节点加速功能,那么由于边缘节点的限制,无法获取客户端 IP。
文件上传
托管在 LeanEngine 的网站项目可以直接使用内置的 LeanCloud Python SDK 的 API 文件相关的接口直接处理文件的上传。
假设前端 HTML 代码如下:
接下来定义文件上传的处理函数,构建一个
Form
对象,并将req
作为参数进行解析,会将请求中的文件保存到临时文件目录,并构造files
对象:Flask:
其他 Web 框架,请参考对应文档。
Session
推荐使用 Web 框架自带的
session
组件。CSRF Token
如果你的云引擎应用使用 Cookie 作为鉴权方式的话(例如使用 SDK 的
CookieSession
中间件),那么就有受到 CSRF 攻击的风险,将会允许其他站点伪造带有正确 Cookie 的恶意请求。业界通常使用 CSRF Token 来防御 CSRF 攻击,你需要传递给客户端一个随机字符串(即 CSRF Token,可通过 Cookie 传递),客户端在每个有副作用的请求中都要将 CSRF 包含在请求正文或 Header 中,服务器端需要校验这个 CSRF Token 是否正确。
LeanCache
LeanCache 是 LeanCloud 为大流量站点提供的一项缓存服务。
要使用 LeanCache,首先将
redis
依赖添加到requirements.txt
中:然后可以使用下列代码获取 Redis 连接:
关于 LeanCache 的更多使用方法请看 LeanCache 使用指南。
重定向到 HTTPS
为了安全性,我们可能会为网站加上 HTTPS 加密传输。我们的 LeanEngine 支持网站托管,同样会有这样的需求。因此我们在 LeanEngine 中提供了一个 middleware 来强制网站通过 HTTPS 访问,你只要这样:
部署并发布到生产环境之后,访问你的 LeanEngine 网站都会强制通过 HTTPS 访问。
部署与发布
命令行部署
在你的项目根目录运行:
使用命令行工具可以非常方便地部署、发布应用,查看应用状态,查看日志,甚至支持多应用部署。具体使用请参考 命令行工具指南。
依赖缓存
云引擎实现了一个缓存机制来加快构建的速度,所谓构建就是指你的应用在云引擎上安装依赖的过程,在每次构建时,如果依赖没有新增或者删减,那么就直接使用上次安装的依赖,只将新的应用代码替换上去。
依赖缓存也会因为很多原因失效,因此不保证每次构建都可以利用上缓存。
如果你遇到了与依赖安装有关的问题,可以在控制台部署时勾选「下载最新依赖」,或通过命令行工具部署时添加
--no-cache
选项。Git 部署
除此之外,还可以使用 git 仓库部署。你需要将项目提交到一个 git 仓库,我们并不提供源码的版本管理功能,而是借助于 git 这个优秀的分布式版本管理工具。我们推荐你使用 GitHub、Coding 或者 码云 这样第三方的源码托管网站,也可以使用你自己搭建的 git 仓库(比如 GitLab)。
你需要先在这些平台上创建一个项目(如果已有代码,请不需要选择「Initialize this repository with a README」),在网站的个人设置中填写本地机器的 SSH 公钥(以 GitHub 为例,在 Settings > SSH and GPG keys 中点击 New SSH key),然后在项目目录执行:
然后到云引擎的设置界面填写你的 Git 仓库地址,如果是公开仓库建议填写 HTTPS 地址,例如
https://github.com/<username>/<repoName>.git
。如果是私有仓库需要填写 SSH 地址(
git@github.com:<username>/<repoName>.git
),还需要你将云引擎分配给你的公钥填写到第三方托管平台的 Deploy keys 中,以 GitHub 为例,在项目的 Settings > Deploy keys 中点击 Add deploy key。设置好之后,今后需要部署代码时就可以在云引擎的部署界面直接点击「部署」了,默认会部署
master
分支的代码,你也可以在部署时填写分支、标签或具体的 Commit。 如果仓库使用了 submodule,云引擎也会自动拉取 submodule。如果希望 push 到项目的 Git 仓库的特定分支后自动触发云引擎部署,可以在应用的 控制台 > 云引擎 > 部署 > git 部署 > 自动部署 查看 deploy token 和 webhook 地址。 控制台显示的 deploy token 可以用来构造 HTTP 请求触发部署。 在控制台填写项目仓库的分支名称,并选择云引擎的运行环境后,控制台会生成相应的 webhook 地址。 该地址收到任意 POST 请求后,会部署指定分支的代码到指定的运行环境。
例如,在 GitHub 代码仓库的 Settings > Webhooks > Payload URL 填写生成的 webhook 后(其他选项均使用默认值,不用修改),下次 push 到项目仓库的 任意 分支,云引擎会自动根据 指定 分支更新代码,重新部署。之所以 push 到任意分支都会触发重新部署,是因为 GitHub 的 webhook 触发事件设置粒度较粗,不能指定仅在 push 到特定分支时触发 webhook。另一方面,云引擎也没有适配具体的托管平台,不会根据 GitHub 提交的 POST 内容中的分支信息决定是否重新部署。 不过,你可以使用 GitHub Action 更精细地控制部署时机,具体可以参考控制台显示的示例。
预备环境和生产环境
默认情况,云引擎只有一个「生产环境」。在生产环境中有一个「体验实例」来运行应用。
当生产环境的体验实例升级到「标准实例」后会有一个额外的「预备环境」。两个环境所访问的都是同样的数据,你可以用预备环境测试你的云引擎代码,每次修改先部署到预备环境,测试通过后再发布到生产环境;如果你希望有一个独立数据源的测试环境,建议单独创建一个应用。
在云引擎托管的网站需要绑定域名才能访问。 以
stg-
开头的域名会自动绑定到预备环境。如果访问云引擎遇到「Application not Found」的错误,通常是因为对应的环境还没有部署代码。例如应用可能没有预备环境,或应用尚未发布代码到生产环境
有些时候你可能需要知道当前云引擎运行在什么环境(开发环境、预备环境或生产环境),从而做不同的处理:
你还可以在 SDK 中指定客户端将请求所发往的环境:
云端环境
系统级依赖
在云引擎的线上环境中,你可以通过
leanengine.yaml
文件的systemDependencies
部分来自定义系统级依赖:目前支持的选项包括:
ffmpeg
一个音视频处理工具库。imagemagick
一个图片处理工具库。fonts-wqy
文泉驿点阵宋体、文泉驿微米黑,通常和phantomjs
或chrome-headless
配合来显示中文。fonts-noto
思源黑体(体积较大)。phantomjs
一个无 UI 的 WebKit 浏览器(该项目已停止维护)。chrome-headless
一个无 UI 的 Chrome 浏览器(体积很大,会显著增加部署耗时,运行时也会消耗大量 CPU 和内存;如果使用puppeter
的话,需要给puppeteer.launch
传递这些参数:{executablePath: '/usr/bin/google-chrome', args: ['--no-sandbox', '--disable-setuid-sandbox']}
;暂不支持 Java)。node-canvas
安装node-canvas
所需要的系统级依赖(你仍需要安装node-canvas
)。python-talib
金融市场数据分析库。注意添加系统依赖将会拖慢部署速度,因此请不要添加未用到的依赖。
环境变量
云引擎平台默认提供下列环境变量供应用使用:
LEANCLOUD_APP_ID
LEANCLOUD_APP_KEY
LEANCLOUD_APP_MASTER_KEY
LEANCLOUD_APP_ENV
development
(一般指本地开发)。stage
。production
。LEANCLOUD_APP_PORT
LEANCLOUD_API_SERVER
https://api.leancloud.cn
)。该值会因为所在数据中心等原因导致不一样,所以使用 REST API 请求存储服务或 LeanCloud 其他服务时请使用此环境变量的值。在云引擎中 不要 直接使用https://api.leancloud.cn
。LEANCLOUD_APP_GROUP
LEANCLOUD_REGION
CN
或US
,分别表示国内版和国际版。LEANCLOUD_VERSION_TAG
旧版云引擎使用的以
LC_
开头的环境变量(如LC_APP_ID
)已经被弃用。为了保证代码兼容性,LC_
变量在一段时间内依然有效,但未来可能会完全失效。为了避免报错,建议使用LEANCLOUD_
变量来替换。你也可以在 控制台 > 云引擎 > 设置 > 自定义环境变量 页面中添加自定义的环境变量。其中名字必须是字母、数字、下划线且以字母开头,值必须是字符串,修改环境变量后会在下一次部署时生效。
按照一般的实践,可以将一些配置项存储在环境变量中,这样可以在不修改代码的情况下,修改环境变量并重新部署,来改变程序的行为;或者可以将一些第三方服务的 Secret Key 存储在环境变量中,避免这些密钥直接出现在代码中。
云引擎运行环境默认提供的环境变量无法被自定义环境变量覆盖(覆盖无效)。
默认情况下,应用在运行阶段才能够读取到内置环境变量和自定义环境变量。 如果希望在安装依赖或编译阶段就能读取到这些环境变量,需要在
leanengine.yaml
里设置:负载均衡和边缘节点
在云引擎上,用户的请求会先经过负载均衡组件,然后到达你的应用。 负载均衡组件会处理 HTTPS 加密、对响应进行压缩等一般性工作,因此你不必在你的应用中添加 HTTPS 或 gzip 相关的功能。 也因为 HTTPS 加密是在负载均衡层面处理的,所以通常部署在云引擎上的 web 框架获取的请求 URL 总是使用 HTTP 协议,建议通过
X-Forwarded-Proto
HTTP 头来判断原请求是通过 HTTP 还是 HTTPS 访问的。负载均衡同时限制了请求不能超过 100 MB(包括直接上传文件到云引擎)、请求处理不得超过 60 秒,WebSocket 60 秒无数据会被断开连接。
国内节点未绑定独立 IP 的云引擎默认为纯静态站点优化。请求会先经过边缘节点,再视缓存命中情况回源到负载均衡组件,最后到达你的应用。 边缘节点额外限制了请求不能超过 60 MB、请求处理不得超过 10 秒,另外边缘节点不支持 WebSocket 请求和 HTTP PATCH 方法,也不支持获取客户端 IP。 因此,如果您在国内节点云引擎托管动态网站,我们建议您绑定独立 IP,使用独立入口,不经过边缘节点,自然也就没有上述限制。
文件系统
你可以向
/home/leanengine
或/tmp
目录写入临时文件,最多不能超过 1 GB。云引擎每次部署都会产生一个新的容器,即使不部署系统偶尔也会进行一些自动调度,这意味着你 不能将本地文件系统当作持久的存储,只能用作临时存储。
如果你写入的文件体积较大,建议在使用后自动删除他们,否则如果占用磁盘空间超过 1 GB,继续写入文件可能会收到类似
Disk quota exceeded
的错误,这种情况下你可以重新部署一下,这样文件就会被清空了。日志
在 控制台 > 云引擎 > 日志 中可以查看云引擎的部署和运行日志,还可以通过日志级别进行筛选。
你还可以 通过命令行工具来导出 最近七天的日志到本地文件,方便进行进一步的分析和统计。
应用的日志可以直接输出到「标准输出」或者「标准错误」,这些信息会分别对应日志的
info
和error
级别,比如下列代码会在info
级别输出'Hello!'
:Python 2:
Python 3:
日志单行最大 4096 个字符,多余部分会被丢弃;日志输出频率大于 600 行/分钟,多余的部分会被丢弃。
云引擎的访问日志(Access Log)可在 控制台 > 云引擎 > 访问日志 中导出,通过控制台下载经过打包的日志。
时区
在云引擎的中国区系统默认使用北京时间(
Asia/Shanghai
),美国区默认使用 UTC 时间。出入口 IP 地址
如果开发者希望在第三方服务平台(如微信开放平台)上配置 IP 白名单而需要获取云引擎的入口或出口 IP 地址,请进入 控制台 > 云引擎 > 设置 > 出入口 IP 来自助查询。
我们会尽可能减少出入口 IP 的变化频率,但 IP 突然变换的可能性仍然存在。因此在遇到与出入口 IP 相关的问题,我们建议先进入控制台来核实一下 IP 列表是否有变化。
备案与自定义域名
根据法律法规和有关部门的要求,使用云引擎网站托管服务需要 绑定自有域名。