网站托管是云引擎的一个子模块,允许你用 PHP 开发一个 Web 程序,提供云函数和 Hook,还可以提供静态文件的托管和自定义的路由、绑定你自己的域名。你可以用它为你的移动应用提供一个介绍和下载页、开发一个管理员控制台或完整的网站,或者运行一些必须在服务器端运行的自定义逻辑。
如果你还不知道如何创建云引擎项目,本地调试并部署到云端,可以先阅读一下 云引擎快速入门。其他相关文档包括:
这篇文档以 PHP 为例,但云引擎还支持其他多种语言,你可以选择自己熟悉的技术栈进行开发:
我们为云引擎支持的各种语言准备了示例项目,建议从示例项目着手开始开发。
要理解如何从示例项目开始开发云引擎项目,本地调试,部署到云端,请先阅读 云引擎快速入门。
你的项目需要遵循一定格式才会被云引擎识别并运行。
LeanEngine PHP 项目必须有 $PROJECT_DIR/public/index.php 文件,该文件为整个项目的启动文件。
$PROJECT_DIR/public/index.php
云引擎默认提供 PHP 5.6 的运行环境,如需指定 PHP 版本,请在 composer.json 中添加:
composer.json
"require": { "php": "7.4.x" }
目前云引擎支持 5.6、7.0、7.1、7.2、7.3、7.4 这几个版本,后续如果有新版本发布,也会添加支持。
5.6
7.0
7.1
7.2
7.3
7.4
所有版本的 PHP 默认开启以下扩展:fpm、curl、mysql、zip、xml、mbstring、gd、soap。 7.0 以上版本的 PHP 还默认开启了 mongodb 扩展。 在 PHP 7.2 中官方从核心中移除了 mcrypt 这个拓展,云引擎以选装的方式继续提供支持,在 composer.json 的 require 中加入 ext-mcrypt: * 即可,使用 mcrypt 会增加部署耗时,如果没有用到请不要加。 如果您需要用到其他扩展,请提交工单联系我们。
fpm
curl
mysql
zip
xml
mbstring
gd
soap
mongodb
mcrypt
require
ext-mcrypt: *
LeanEngine PHP 不依赖第三方框架,你可以使用你最熟悉的框架进行开发,或者不使用任何框架。但是请保证通过执行 public/index.php 能够启动你的项目。
public/index.php
对于 PHP 项目,我们默认每 64 MB 内存分配一个 PHP-FPM Worker,如果希望自定义 Worker 数量,可以在云引擎设置页面的「自定义环境变量」中添加名为 PHP_WORKERS 的环境变量,值是一个数字。设置过低会导致收到新请求时无可用的 Worker;过高会导致内存不足、请求处理失败,建议谨慎调整。
PHP_WORKERS
在项目中存在 composer.lock 文件时,云引擎会优先根据 composer.lock 安装依赖。
composer.lock
由于构建时会复制 composer.json 和 composer.lock 到专门的目录安装依赖,因此不支持 path 类型的 composer 本地仓库。 如果您的项目使用了 path 类型的本地仓库,我们建议改为 vcs 类型。
path
vcs
云引擎使用 LeanCloud PHP SDK,实际包含了存储 SDK,可以直接使用相关接口来存储数据。请参考 PHP 存储文档。
如果使用项目框架作为基础开发,LeanCloud PHP SDK 默认提供了支持 Slim 框架 的中间件,可以根据示例程序的方式直接使用。
如果是自定义项目,则需要自己配置:
首先安装 composer。
composer
配置依赖:在项目根目录下执行以下命令来增加 LeanCloud PHP SDK 的依赖:
composer require leancloud/leancloud-sdk
初始化:在正式使用数据存储之前,你需要使用自己的 App Key 进行初始化中间件:
use \LeanCloud\Client; Client::initialize( getenv("LEANCLOUD_APP_ID"), // 从 LEANCLOUD_APP_ID 这个环境变量中获取应用 App ID 的值 getenv("LEANCLOUD_APP_KEY"), // 从 LEANCLOUD_APP_KEY 这个环境变量中获取应用 App Key 的值 getenv("LEANCLOUD_APP_MASTER_KEY") // 从 LEANCLOUD_APP_MASTER_KEY 这个环境变量中获取应用 Master Key 的值 ); // 如果不希望使用 Master Key 权限,可以将下面一行删除 Client::useMasterKey(true);
你的应用在启动时,云引擎的管理程序会每秒去检查你的应用是否启动成功,如果 30 秒 仍未启动成功,即认为启动失败;在之后应用正常运行的过程中,也会有定期的「健康监测」,以确保你的应用正常运行,如果健康监测失败,云引擎管理程序会自动重启你的应用。
健康检查的 URL 包括你的应用首页(/)和 PHP SDK 负责处理的 /__engine/1/ping,只要 两者之一 返回了 HTTP 200 的响应,就视作成功。因此请确保你的程序使用了 PHP SDK,或你的应用 首页能够正常地返回 HTTP 200 响应。除此之外,为了支持云引擎的云函数和 Hook 功能,管理程序会使用 /1.1/functions/_ops/metadatas 这个 URL 和 PHP SDK 交互,请确保将这个 URL 交给 PHP SDK 处理,或 返回一个 HTTP 404 表示不使用云函数和 Hook 相关的功能。
/
/__engine/1/ping
200
/1.1/functions/_ops/metadatas
404
LeanCloud PHP SDK 内置了该 URL 的处理,只需要将中间件添加到请求的处理链路中即可:
$engine = new SlimEngine(); $app->add($engine);
如果未使用 LeanCloud PHP SDK,则需要自己实现该 URL 的处理,比如这样:
// 健康监测 router $app->get('/__engine/1/ping', function($req, $res) { // PSR-7 response is immutable $response = $res->withHeader("Content-Type", "application/json"); $response->getBody()->write(json_encode(array( "runtime" => "php-" . phpversion(), "version" => "custom" ))); return $response; }); // 云函数列表 app.get('/1.1/_ops/functions/metadatas', function(req, res) { $response = $res->withHeader("Content-Type", "application/json"); $response->getBody()->write(json_encode(array( "result" => array() ))); return $response; });
云引擎提供了一个 LeanCloud\Storage\CookieStorage 模块,用 Cookie 来维护用户(User)的登录状态,要使用它可以在 app.php 中添加下列代码:
LeanCloud\Storage\CookieStorage
User
app.php
use \LeanCloud\Storage\CookieStorage; // 将会话状态存储到 cookie 中 Client::setStorage(new CookieStorage(60 * 60 * 24, "/"));
CookieStorage 支持传入秒作为过期时间,以及路径作为 cookie 的作用域。默认过期时间为 7 天
CookieStorage
可以通过 User::getCurrentUser() 来获取当前登录用户。你可以这样简单地实现一个具有登录功能的站点:
User::getCurrentUser()
$app->get('/login', function($req, $res) { // 渲染登录页面 }); // 处理登录请求(可能来自登录界面中的表单) $app->post('/login', function($req, $res) { $params = $req->getQueryParams(); try { User::logIn($params["username"], $params["password"]); // 跳转到个人资料页面 return $res->withRedirect('/profile'); } catch (Exception $ex) { // 登录失败,跳转到登录页面 return $res->withRedirect('/login'); } }); // 查看个人资料 $app->get('/profile', function($req, $res) { // 判断用户是否已经登录 $user = User::getCurrentUser(); if ($user) { // 如果已经登录,发送当前登录用户信息 return $res->getBody()->write($user->getUsername()); } else { // 如果没有登录,跳转到登录页面 return $res->withRedirect('/login'); } }); // 登出账号 $app->get('/logout', function($req, $res) { User::logOut(); return $res->redirect("/"); });
一个简单的登录页面可以是这样:
<html> <head></head> <body> <form method="post" action="/login"> <label>Username</label> <input name="username"> <label>Password</label> <input name="password" type="password"> <input class="button" type="submit" value="登录"> </form> </body> </html>
云引擎 PHP 环境可以使用内置的 curl 模块,不过我们推荐使用 guzzle 等第三方库来处理 HTTP 请求。
安装 guzzle:
guzzle
composer require guzzlehttp/guzzle:~6.0
代码示例:
$client = new GuzzleHttp\Client(); $resp = $client->post("http://www.example.com/create_post", array( "json" => array( "title" => "Some Amazing Title", "body" => "Some awesome content." ) ));
如果你想获取客户端的 IP,可以直接从用户请求的 HTTP 头的 x-real-ip 字段获取,示例代码如下:
x-real-ip
$app->get('/', function($req, $res) { error_log($_SERVER['HTTP_X_REAL_IP]); // Print user IP address return $res; });
注意,国内节点的云引擎应用,如果启用了边缘节点加速功能,那么由于边缘节点的限制,无法获取客户端 IP。
托管在 LeanEngine 的网站项目可以直接使用内置的 LeanCloud PHP 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->post("/upload", function($req, $res) { if (isset($_FILES["iconImage"]) && $_FILES["iconImage"]["size"] != 0) { $file = File::createWithLocalFile( $_FILES["iconImage"]["tmp_name"], $_FILES["iconImage"]["type"] ); $file->save(); $res->getBody()->write("上传成功!"); } else { $res->getBody()->write("请选择一个文件。"); } });
如果你需要将一些属性保存在 session 中,可以增加通用的 CookieStorage 来保存:
// 在项目启动时启用 CookieStorage Client::setStorage(new CookieStorage()); // 在项目中可以使用 CookieStorage 存储属性 $cookieStorage = Client::getStorage(); $cookieStorage->set("key", "val");
PHP 默认的 $_SESSION 在我们云引擎中是无法正常工作的,因为我们的云引擎是多主机、多进程运行,因此内存型 session 是无法共享的。建议用 CookieStorage 来存储会话信息。
$_SESSION
如果你的云引擎应用使用 Cookie 作为鉴权方式的话(例如使用 SDK 的 CookieSession中间件),那么就有受到 CSRF 攻击的风险,将会允许其他站点伪造带有正确 Cookie 的恶意请求。
CookieSession
业界通常使用 CSRF Token 来防御 CSRF 攻击,你需要传递给客户端一个随机字符串(即 CSRF Token,可通过 Cookie 传递),客户端在每个有副作用的请求中都要将 CSRF 包含在请求正文或 Header 中,服务器端需要校验这个 CSRF Token 是否正确。
为了安全性,我们可能会为网站加上 HTTPS 加密传输。我们的 LeanEngine 支持网站托管,同样会有这样的需求。因此我们在 LeanEngine 中提供了一个 middleware 来强制网站通过 HTTPS 访问,你只要这样:
SlimEngine::enableHttpsRedirect(); $app->add(new SlimEngine());
部署并发布到生产环境之后,访问你的 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」的错误,通常是因为对应的环境还没有部署代码。例如应用可能没有预备环境,或应用尚未发布代码到生产环境
有些时候你可能需要知道当前云引擎运行在什么环境(开发环境、预备环境或生产环境),从而做不同的处理:
$env = getenv("LEANCLOUD_APP_ENV"); if ($env === "development") { // 当前环境为「开发环境」,是由命令行工具启动的 } else if ($env === "production") { // 当前环境为「生产环境」,是线上正式运行的环境 } else { // 当前环境为「预备环境」 }
你还可以在 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); // 预备环境
LCCloud.IsProduction = true; // 生产环境(默认) LCCloud.IsProduction = false; // 预备环境
在控制台 > 云引擎 > 云引擎分组 > 部署页面可以分别查看预备环境和生产环境的历史部署。 每个历史部署版本会显示简短描述(基于 git 提交日志等信息)、部署版本号、部署时间。 历史部署按部署时间倒序排列,当前部署排在最前。 点击回滚至该版本按钮,可以回滚至相应的部署版本。 点击查看更多历史部署可以查看最近部署的 10 个版本。 除了按预备环境和生产环境分别查看历史部署外,点击右上角的查看部署时间线则可以按照时间顺序(最新部署在前)查看部署到云引擎的各个版本。
除了查看部署历史外,这里还会显示预备环境或生产环境的部署状态(「休眠中」、「部署中」、「运行中」)。 通过右上角的按钮还可以重启(重新部署当前版本)或清除部署(移除部署,注销相应的云函数和 Hook)。 预备环境还可以点击右上角的部署到生产环境按钮将最近部署到预备环境的版本发布到生产环境。 当部署状态为「部署中」时,控制台会显示部署进行中的一些信息,也会显示一个取消部署按钮,点击可以取消部署。
在云引擎的线上环境中,你可以通过 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 存储在环境变量中,避免这些密钥直接出现在代码中。
云引擎运行环境默认提供的环境变量无法被自定义环境变量覆盖(覆盖无效)。
默认情况下,应用在运行阶段才能够读取到内置环境变量和自定义环境变量。 如果希望在安装依赖或编译阶段就能读取到这些环境变量,需要在 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
在 控制台 > 云引擎 > 云引擎分组 > 日志 中可以查看云引擎的部署和运行日志,还可以通过环境(预备环境、生产环境)、类型(标准输出、标准错误)、实例、日期时间进行筛选。
你还可以 通过命令行工具来导出 最近七天的日志到本地文件,方便进行进一步的分析和统计。
日志单行最大 4096 个字符,多余部分会被丢弃;日志输出频率大于 600 行/分钟,多余的部分会被丢弃。
云引擎的访问日志(Access Log)可以在控制台导出。
在云引擎的中国区系统默认使用北京时间(Asia/Shanghai),美国区默认使用 UTC 时间。
Asia/Shanghai
如果开发者希望在第三方服务平台(如微信开放平台)上配置 IP 白名单而需要获取云引擎的入口或出口 IP 地址,请进入 控制台 > 云引擎 > 设置 > 出入口 IP 来自助查询。
我们会尽可能减少出入口 IP 的变化频率,但 IP 突然变换的可能性仍然存在。因此在遇到与出入口 IP 相关的问题,我们建议先进入控制台来核实一下 IP 列表是否有变化。
根据法律法规和有关部门的要求,使用云引擎网站托管服务需要 绑定自有域名。
网站托管开发指南 · PHP
网站托管是云引擎的一个子模块,允许你用 PHP 开发一个 Web 程序,提供云函数和 Hook,还可以提供静态文件的托管和自定义的路由、绑定你自己的域名。你可以用它为你的移动应用提供一个介绍和下载页、开发一个管理员控制台或完整的网站,或者运行一些必须在服务器端运行的自定义逻辑。
如果你还不知道如何创建云引擎项目,本地调试并部署到云端,可以先阅读一下 云引擎快速入门。其他相关文档包括:
这篇文档以 PHP 为例,但云引擎还支持其他多种语言,你可以选择自己熟悉的技术栈进行开发:
从示例项目开始
我们为云引擎支持的各种语言准备了示例项目,建议从示例项目着手开始开发。
要理解如何从示例项目开始开发云引擎项目,本地调试,部署到云端,请先阅读 云引擎快速入门。
项目骨架
你的项目需要遵循一定格式才会被云引擎识别并运行。
LeanEngine PHP 项目必须有
$PROJECT_DIR/public/index.php
文件,该文件为整个项目的启动文件。云引擎默认提供 PHP 5.6 的运行环境,如需指定 PHP 版本,请在
composer.json
中添加:目前云引擎支持
5.6
、7.0
、7.1
、7.2
、7.3
、7.4
这几个版本,后续如果有新版本发布,也会添加支持。所有版本的 PHP 默认开启以下扩展:
fpm
、curl
、mysql
、zip
、xml
、mbstring
、gd
、soap
。 7.0 以上版本的 PHP 还默认开启了mongodb
扩展。 在 PHP 7.2 中官方从核心中移除了mcrypt
这个拓展,云引擎以选装的方式继续提供支持,在composer.json
的require
中加入ext-mcrypt: *
即可,使用mcrypt
会增加部署耗时,如果没有用到请不要加。 如果您需要用到其他扩展,请提交工单联系我们。LeanEngine PHP 不依赖第三方框架,你可以使用你最熟悉的框架进行开发,或者不使用任何框架。但是请保证通过执行
public/index.php
能够启动你的项目。对于 PHP 项目,我们默认每 64 MB 内存分配一个 PHP-FPM Worker,如果希望自定义 Worker 数量,可以在云引擎设置页面的「自定义环境变量」中添加名为
PHP_WORKERS
的环境变量,值是一个数字。设置过低会导致收到新请求时无可用的 Worker;过高会导致内存不足、请求处理失败,建议谨慎调整。在项目中存在
composer.lock
文件时,云引擎会优先根据 composer.lock 安装依赖。由于构建时会复制
composer.json
和composer.lock
到专门的目录安装依赖,因此不支持path
类型的 composer 本地仓库。 如果您的项目使用了path
类型的本地仓库,我们建议改为vcs
类型。使用数据存储服务
云引擎使用 LeanCloud PHP SDK,实际包含了存储 SDK,可以直接使用相关接口来存储数据。请参考 PHP 存储文档。
如果使用项目框架作为基础开发,LeanCloud PHP SDK 默认提供了支持 Slim 框架 的中间件,可以根据示例程序的方式直接使用。
如果是自定义项目,则需要自己配置:
首先安装
composer
。配置依赖:在项目根目录下执行以下命令来增加 LeanCloud PHP SDK 的依赖:
初始化:在正式使用数据存储之前,你需要使用自己的 App Key 进行初始化中间件:
健康监测
你的应用在启动时,云引擎的管理程序会每秒去检查你的应用是否启动成功,如果 30 秒 仍未启动成功,即认为启动失败;在之后应用正常运行的过程中,也会有定期的「健康监测」,以确保你的应用正常运行,如果健康监测失败,云引擎管理程序会自动重启你的应用。
健康检查的 URL 包括你的应用首页(
/
)和 PHP SDK 负责处理的/__engine/1/ping
,只要 两者之一 返回了 HTTP200
的响应,就视作成功。因此请确保你的程序使用了 PHP SDK,或你的应用 首页能够正常地返回 HTTP200
响应。除此之外,为了支持云引擎的云函数和 Hook 功能,管理程序会使用/1.1/functions/_ops/metadatas
这个 URL 和 PHP SDK 交互,请确保将这个 URL 交给 PHP SDK 处理,或 返回一个 HTTP404
表示不使用云函数和 Hook 相关的功能。LeanCloud PHP SDK 内置了该 URL 的处理,只需要将中间件添加到请求的处理链路中即可:
如果未使用 LeanCloud PHP SDK,则需要自己实现该 URL 的处理,比如这样:
用户状态管理
云引擎提供了一个
LeanCloud\Storage\CookieStorage
模块,用 Cookie 来维护用户(User
)的登录状态,要使用它可以在app.php
中添加下列代码:CookieStorage
支持传入秒作为过期时间,以及路径作为 cookie 的作用域。默认过期时间为 7 天可以通过
User::getCurrentUser()
来获取当前登录用户。你可以这样简单地实现一个具有登录功能的站点:一个简单的登录页面可以是这样:
实现常见的网站功能
发送 HTTP 请求
云引擎 PHP 环境可以使用内置的
curl
模块,不过我们推荐使用 guzzle 等第三方库来处理 HTTP 请求。安装
guzzle
:代码示例:
获取客户端 IP
如果你想获取客户端的 IP,可以直接从用户请求的 HTTP 头的
x-real-ip
字段获取,示例代码如下:注意,国内节点的云引擎应用,如果启用了边缘节点加速功能,那么由于边缘节点的限制,无法获取客户端 IP。
文件上传
托管在 LeanEngine 的网站项目可以直接使用内置的 LeanCloud PHP SDK 的 API 文件相关的接口直接处理文件的上传。
假设前端 HTML 代码如下:
接下来定义文件上传的处理函数,构建一个
Form
对象,并将req
作为参数进行解析,会将请求中的文件保存到临时文件目录,并构造files
对象:Session
如果你需要将一些属性保存在 session 中,可以增加通用的
CookieStorage
来保存:PHP 默认的
$_SESSION
在我们云引擎中是无法正常工作的,因为我们的云引擎是多主机、多进程运行,因此内存型 session 是无法共享的。建议用CookieStorage
来存储会话信息。CSRF Token
如果你的云引擎应用使用 Cookie 作为鉴权方式的话(例如使用 SDK 的
CookieSession
中间件),那么就有受到 CSRF 攻击的风险,将会允许其他站点伪造带有正确 Cookie 的恶意请求。业界通常使用 CSRF Token 来防御 CSRF 攻击,你需要传递给客户端一个随机字符串(即 CSRF Token,可通过 Cookie 传递),客户端在每个有副作用的请求中都要将 CSRF 包含在请求正文或 Header 中,服务器端需要校验这个 CSRF Token 是否正确。
重定向到 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 中指定客户端将请求所发往的环境:
部署历史
在控制台 > 云引擎 > 云引擎分组 > 部署页面可以分别查看预备环境和生产环境的历史部署。 每个历史部署版本会显示简短描述(基于 git 提交日志等信息)、部署版本号、部署时间。 历史部署按部署时间倒序排列,当前部署排在最前。 点击回滚至该版本按钮,可以回滚至相应的部署版本。 点击查看更多历史部署可以查看最近部署的 10 个版本。 除了按预备环境和生产环境分别查看历史部署外,点击右上角的查看部署时间线则可以按照时间顺序(最新部署在前)查看部署到云引擎的各个版本。
除了查看部署历史外,这里还会显示预备环境或生产环境的部署状态(「休眠中」、「部署中」、「运行中」)。 通过右上角的按钮还可以重启(重新部署当前版本)或清除部署(移除部署,注销相应的云函数和 Hook)。 预备环境还可以点击右上角的部署到生产环境按钮将最近部署到预备环境的版本发布到生产环境。 当部署状态为「部署中」时,控制台会显示部署进行中的一些信息,也会显示一个取消部署按钮,点击可以取消部署。
云端环境
系统级依赖
在云引擎的线上环境中,你可以通过
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
的错误,这种情况下你可以重新部署一下,这样文件就会被清空了。日志
在 控制台 > 云引擎 > 云引擎分组 > 日志 中可以查看云引擎的部署和运行日志,还可以通过环境(预备环境、生产环境)、类型(标准输出、标准错误)、实例、日期时间进行筛选。
你还可以 通过命令行工具来导出 最近七天的日志到本地文件,方便进行进一步的分析和统计。
日志单行最大 4096 个字符,多余部分会被丢弃;日志输出频率大于 600 行/分钟,多余的部分会被丢弃。
云引擎的访问日志(Access Log)可以在控制台导出。
时区
在云引擎的中国区系统默认使用北京时间(
Asia/Shanghai
),美国区默认使用 UTC 时间。出入口 IP 地址
如果开发者希望在第三方服务平台(如微信开放平台)上配置 IP 白名单而需要获取云引擎的入口或出口 IP 地址,请进入 控制台 > 云引擎 > 设置 > 出入口 IP 来自助查询。
我们会尽可能减少出入口 IP 的变化频率,但 IP 突然变换的可能性仍然存在。因此在遇到与出入口 IP 相关的问题,我们建议先进入控制台来核实一下 IP 列表是否有变化。
备案与自定义域名
根据法律法规和有关部门的要求,使用云引擎网站托管服务需要 绑定自有域名。