本文介绍如何在阿里云云服务器ECS上基于Alibaba Cloud Linux 3操作系统搭建高可用的微信小程序服务端,并在本地开发一个名为ECS小助手的简单微信小程序。通过远程调用部署在ECS上的服务端,实现在小程序中输入框输入ECS实例ID查询实例详细信息的功能。
步骤一:准备环境和资源
部署高可用的小程序服务需要2台ECS实例(Alibaba Cloud Linux3.2104 LTS 64位)、1台CLB实例。具体操作,请参见ECS实例创建方式介绍和创建和管理CLB实例。
本教程配置:
云服务器ECS
地域:华北2(北京)
操作系统:Alibaba Cloud Linux3.2104 LTS 64位
实例规格配置:1核2 GB
实例数量:2(ECS01、ECS02)
其他参数:保持默认值或按需选择
传统型负载均衡CLB
地域与可用区:选择与ECS实例相同的地域,本教程选择华北2(北京)
实例规格配置:按需创建
实例计费方式:按使用量计费
实例类型:公网
实例数量:1
IP 版本:IPv4
步骤二:配置资源并搭建服务
一键配置
通过ROS一键部署
准备好资源后,您可以通过一键配置快速完成资源配置或应用搭建。一键配置基于阿里云资源编排服务ROS(Resource Orchestration Service)实现,旨在帮助开发者通过IaC(Infrastructure as Code)的方式体验资源的自动化配置。如需查看软件版本、安装命令等配置的具体信息,可查看教程的手动配置版。模板完成的内容包括:
为ECS实例配置安全组
创建角色并绑定到ECS实例
安装Nginx服务并写入配置
安装uWSGI Server并写入配置
安装Python环境并写入代码
操作步骤
打开一键配置模板链接前往ROS控制台,单击上一步:选择模板,在模板内容区域展示了YAML文件的详细信息。
ROS控制台默认处于您上一次访问控制台时的地域,请根据您创建的资源所在地域修改地域,例如选择华北2(北京)地域,保持页面所有选项不变,单击下一步:配置参数。
在配置参数页面,修改资源栈名称,选择您申请免费试用时创建的ECS实例,设置要创建的用于ECS实例扮演的角色名称,选择创建的CLB实例(原SLB实例)。填写完所有必选信息并确认后单击下一步:检查并确认。
确认各项配置信息无误后,单击创建。
在资源栈信息页签下的基本信息区域中,查看状态显示为创建成功时表示一键配置完成。
通过Terraform一键部署
Terraform是一款IaC工具(Infrastructure as Code),能够帮助开发人员和运维团队自动化基础设施的创建、部署和管理。您可以通过编写简洁的代码来定义和配置云端基础设施,而不必手动操作和配置。
操作步骤
点击一键运行进入Terraform Explorer,自动加载如下的Terraform代码。
provider "alicloud" { region = var.region } variable "region" { description = "Region where resources will be created" default = "cn-beijing" } variable "common_name" { default = "deploy-java-web-by-terraform" description = "Common name for resources" } variable "system_disk_category" { default = "cloud_essd" description = "The category of the system disk." } variable "instance_password" { default = "Test@123456" description = "Server login password" } variable "image_id" { default = "aliyun_3_x64_20G_alibase_20240528.vhd" description = "Please choose the Alibaba Cloud Linux 3 Image ID for the instance" } variable "instance_type" { description = "Instance type" default = "ecs.e-c1m2.large" } variable "instance_count" { description = "The number of ECS instances to create." default = "2" } variable "ecs_ram_role_name" { description = "English letters, numbers, or ' - ' are allowed. The number of characters should be less than or equal to 64." default = "EcsRoleForMiniProgramServer" } data "alicloud_zones" "default" { available_disk_category = var.system_disk_category available_resource_creation = "VSwitch" available_instance_type = var.instance_type } resource "alicloud_ram_role" "role" { name = var.ecs_ram_role_name document = <<EOF { "Statement": [ { "Action": "sts:AssumeRole", "Effect": "Allow", "Principal": { "Service": [ "ecs.aliyuncs.com" ] } } ], "Version": "1" } EOF description = "Ecs ram role." force = true } resource "alicloud_ram_policy" "policy" { policy_name = "${var.ecs_ram_role_name}Policy" policy_document = <<EOF { "Statement": [ { "Action": [ "ecs:DescribeInstances", "ecs:DescribeInstanceStatus" ], "Effect": "Allow", "Resource": ["*"] } ], "Version": "1" } EOF description = "this is a policy test" force = true } resource "alicloud_ram_role_policy_attachment" "attach" { policy_name = alicloud_ram_policy.policy.policy_name policy_type = "Custom" role_name = alicloud_ram_role.role.name } resource "alicloud_vpc" "vpc" { vpc_name = "${var.common_name}-vpc" cidr_block = "192.168.0.0/16" } resource "alicloud_vswitch" "vswitch" { vpc_id = alicloud_vpc.vpc.id vswitch_name = "${var.common_name}-vsw" cidr_block = "192.168.0.0/24" zone_id = data.alicloud_zones.default.zones.0.id } resource "alicloud_security_group" "sg" { security_group_name = "${var.common_name}-sg" vpc_id = alicloud_vpc.vpc.id description = "Security group for ECS instance" } resource "alicloud_security_group_rule" "allow_ssh" { type = "ingress" ip_protocol = "tcp" nic_type = "intranet" policy = "accept" port_range = "22/22" priority = 1 security_group_id = alicloud_security_group.sg.id cidr_ip = "0.0.0.0/0" } resource "alicloud_security_group_rule" "allow_80" { type = "ingress" ip_protocol = "tcp" nic_type = "intranet" policy = "accept" port_range = "80/80" priority = 1 security_group_id = alicloud_security_group.sg.id cidr_ip = "0.0.0.0/0" } resource "alicloud_ram_role_attachment" "attach" { role_name = alicloud_ram_role.role.name instance_ids = alicloud_instance.ecs_instance.*.id } resource "alicloud_instance" "ecs_instance" { count = var.instance_count instance_name = "${var.common_name}-ecs" image_id = var.image_id instance_type = var.instance_type security_groups = alicloud_security_group.sg.*.id vswitch_id = alicloud_vswitch.vswitch.id password = var.instance_password internet_max_bandwidth_out = 100 system_disk_category = var.system_disk_category } resource "alicloud_eip_address" "eip" { description = "${var.common_name}-eip" address_name = "${var.common_name}-eip" netmode = "public" bandwidth = "5" } resource "alicloud_eip_association" "clb_ip" { allocation_id = alicloud_eip_address.eip.id instance_id = alicloud_slb_load_balancer.instance.id } resource "alicloud_slb_load_balancer" "instance" { load_balancer_name = "${var.common_name}-clb" load_balancer_spec = "slb.s2.small" internet_charge_type = "PayByTraffic" address_type = "intranet" vswitch_id = alicloud_vswitch.vswitch.id } resource "alicloud_slb_listener" "listener" { load_balancer_id = alicloud_slb_load_balancer.instance.id backend_port = 80 frontend_port = 80 protocol = "http" bandwidth = -1 health_check = "on" health_check_uri = "/" health_check_connect_port = 80 healthy_threshold = 3 unhealthy_threshold = 3 health_check_timeout = 5 health_check_interval = 2 health_check_http_code = "http_2xx,http_3xx" } resource "alicloud_slb_attachment" "default" { load_balancer_id = alicloud_slb_load_balancer.instance.id instance_ids = alicloud_instance.ecs_instance.*.id weight = 80 } resource "alicloud_ecs_command" "deploy" { name = "DeployMiniProgramServer" type = "RunShellScript" command_content = base64encode(local.command_content) timeout = 3600 working_dir = "/root" } resource "alicloud_ecs_invocation" "invocation" { instance_id = alicloud_instance.ecs_instance.*.id command_id = alicloud_ecs_command.deploy.id timeouts { create = "10m" } } locals { command_content = <<EOF #!/bin/bash if [ ! -f .tf.provision ]; then echo "Name: 搭建小程序" > .tf.provision fi name=$(grep "^Name:" .tf.provision | awk -F':' '{print $2}' | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//') if [ "$name" != "搭建小程序" ]; then echo "当前实例已使用过\"$name\"教程的一键配置,不能再使用本教程的一键配置" exit 0 fi if ! grep -q "^Step1: Install Python$" .tf.provision; then echo "#########################" echo "# Install Python" echo "#########################" mkdir /data && touch /data/GetServerInfo.py cat > /data/GetServerInfo.py << EOF2 # -*- coding: utf-8 -*- from flask import Flask, jsonify, request from alibabacloud_credentials.client import Client as CredClient from alibabacloud_credentials.models import Config as CredConfig from alibabacloud_ecs20140526 import models as ecs_20140526_models from alibabacloud_ecs20140526.client import Client as EcsClient from alibabacloud_tea_openapi.models import Config app = Flask(__name__) ecs_ram_role = '${var.ecs_ram_role_name}' region = '${var.region}' # 用于健康检查 @app.route('/', methods=['HEAD', 'GET']) def index(): return "ok" # 在app.route装饰器中声明响应的URL和请求方法 Declare the URL and request method of the response in the app.route decorator. @app.route('/ecs/getServerInfo', methods=['GET']) def get_server_info(): cred_config = CredConfig( type='ecs_ram_role', role_name=ecs_ram_role, ) cred_client = CredClient(cred_config) ecs_config = Config(credential=cred_client, region_id=region) ecs_client = EcsClient(ecs_config) # GET方式获取请求参数 Get request parameters. instance_id = request.args.get("instanceId") if instance_id is None: return "Invalid Parameter" instance_ids = [instance_id] # 查询实例信息 Query instance information. describe_instances_request = ecs_20140526_models.DescribeInstancesRequest() describe_instances_request.region_id = region describe_instances_request.instance_ids = str(instance_ids) describe_instances_response = ecs_client.describe_instances(describe_instances_request) # 返回数据为bytes类型,需要将bytes类型转换为str然后反序列化为json对象 The returned data is of type bytes, which needs to be converted to str and then deserialized into a json object. if len(describe_instances_response.to_map()['body']['Instances']['Instance']) == 0: return jsonify({}) instance_info = describe_instances_response.to_map()['body']['Instances']['Instance'][0] # 查询实例状态 Query instance status. describe_instance_status_request = ecs_20140526_models.DescribeInstanceStatusRequest() describe_instance_status_request.region_id = region describe_instance_status_request.instance_id = instance_ids describe_instance_status_response = ecs_client.describe_instance_status(describe_instance_status_request) instance_status = describe_instance_status_response.to_map()['body']['InstanceStatuses']['InstanceStatus'][0][ 'Status'] # 封装结果 result result = { # cpu数 'Cpu': instance_info['Cpu'], # 内存大小 'Memory': instance_info['Memory'], # 操作系统名称 'OSName': instance_info['OSName'], # 实例规格 'InstanceType': instance_info['InstanceType'], # 实例公网IP地址 'IpAddress': instance_info['PublicIpAddress']['IpAddress'][0], # 公网出带宽最大值 'InternetMaxBandwidthOut': instance_info['InternetMaxBandwidthOut'], # 实例状态 'instance_status': instance_status } return jsonify(result) if __name__ == "__main__": app.run() EOF2 touch /data/requirements.txt cat > /data/requirements.txt << EOF2 wheel alibabacloud_ecs20140526 Flask==2.0.3 EOF2 pip3 install --upgrade pip && pip3 install -r /data/requirements.txt echo "Step1: Install Python" >> .tf.provision else echo "#########################" echo "# Python has been installed" echo "#########################" fi if ! grep -q "^Step2: Install uWSGI Server$" .tf.provision; then echo "#########################" echo "# Install uWSGI Server" echo "#########################" pip3 install uwsgi touch /data/uwsgi.ini cat > /data/uwsgi.ini << EOF2 [uwsgi] #uwsgi启动时所使用的地址和端口 The address and port used when uwsgi starts. socket=127.0.0.1:5000 #指向网站目录 site directory. chdir=/data #python启动程序文件 python start file. wsgi-file=GetServerInfo.py #python程序内用以启动的application变量名 The application variable name used to start in the python program. callable=app #处理器数 Processors. processes=1 #线程数 Threads. threads=2 #状态检测地址 status detection address. stats=127.0.0.1:9191 #保存启动之后主进程的pid Save the pid file of the main process after startup. pidfile=/data/uwsgi.pid #设置uwsgi后台运行,uwsgi.log保存日志信息 自动生成 save log info file. daemonize=/data/uwsgi.log EOF2 uwsgi /data/uwsgi.ini echo "Step2: Install uWSGI Server" >> .tf.provision else echo "#########################" echo "# uWSGI Server has been installed" echo "#########################" fi if ! grep -q "^Step3: Install Nginx$" .tf.provision; then echo "#########################" echo "# Install Nginx" echo "#########################" yum install -y nginx touch /etc/nginx/conf.d/app.conf cat > /etc/nginx/conf.d/app.conf << EOF2 server { listen 80 default_server; server_name app.example.com; root /var/www/html; # Add index.php to the list if you are using PHP index index.html index.htm index.nginx-debian.html; location / { # 转发端口 forwarding address. uwsgi_pass 127.0.0.1:5000; include uwsgi_params; } } EOF2 systemctl start nginx echo "Step3: Install Nginx" >> .tf.provision else echo "#########################" echo "# Nginx has been installed" echo "#########################" fi EOF } output "public_ip" { value = alicloud_eip_address.eip.ip_address }
根据实际情况修改参数,默认情况下,将会在cn-beijing创建1个VPC实例、2台操作系统为Alibaba Cloud Linux 3的按量付费ECS实例、1个按量付费CLB实例、1个按量付费EIP实例和1个RAM角色。关于各个实例计费说明,请分别查阅以下文档:
单击发起调试,预览待创建资源详细信息,若资源信息无误,单击预览并执行开始创建资源。当任务的执行详情状态为执行成功时,说明已部署完成。
验证服务部署情况。在浏览器中输入以下内容,其中<clb_public_ip>应替换为Terraform输出的IP地址。
http://<clb_public_ip>/ecs/getServerInfo
若命令执行结果是
Invalid Parameter
,则表示服务部署成功。
手动配置
您可参考以下步骤,手动配置ECS及CLB实例:
步骤一:创建RAM角色并绑定到ECS实例
创建好实例后,您需要创建RAM角色并关联到ECS实例,用于后端服务调用SDK。
在实例内部基于STS(Security Token Service)临时凭证访问云产品的API,临时凭证将周期性更新。既可以保证云账号AccessKey的安全,还可以借助访问控制RAM实现精细化控制和权限管理。
创建实例RAM角色。
使用RAM管理员登录RAM控制台。
在左侧导航栏,选择 。
在角色页面,单击创建角色。
在创建角色面板,选择可信实体类型选择为阿里云服务,然后单击下一步。
阿里云服务用于授权ECS实例访问或管理您的云资源。RAM角色选择阿里云服务类型后,支持授予给ECS实例。
选择角色类型为普通服务角色。
输入角色名称和备注。
选择受信服务为云服务器。
单击完成。
单击关闭。
创建自定义策略。在下面为RAM角色授予权限时,选择这里创建的策略。
使用阿里云账号登录RAM控制台。
在左侧导航栏,选择
。在权限策略页面,单击创建权限策略。
在创建权限策略页面,单击脚本编辑页签。
输入权限策略内容,然后单击确定。
{ "Version": "1", "Statement": [ { "Effect": "Allow", "Action": [ "ecs:DescribeInstances", "ecs:DescribeInstanceStatus" ], "Resource": "*" } ] }
输入权限策略名称(例如
EcsRamRolePolicyTest
)和备注。单击确定。
为RAM角色授予权限。
为实例授予RAM角色。
登录ECS管理控制台。
在左侧导航栏,选择 。
在顶部菜单栏左上角处,选择ECS实例所在地域。例如华北2(北京)。
找到待操作的ECS实例,选择
。在弹出的对话框中,选择已创建好的实例RAM角色,单击确定完成授予。
步骤二:登录云服务器
开通免费试用ECS服务器后,系统会创建一个ECS实例(对应一台云服务器),使用ECS实例部署应用或搭建环境前,需设置该ECS实例密码后才能登录实例。
登录ECS控制台。
在左侧导航栏,选择
。在顶部菜单栏左上角处,选择和试用实例相同的地域。
设置ECS实例的登录密码。
在ECS实例对应操作列,选择
,按照界面提示设置ECS实例的登录密码,然后单击确认修改。重要实例创建完成大约3~5分钟后,才支持重置实例密码,如不可重置请您耐心等待后重试。
(可选)在弹出的对话框中,单击立即重启实例,使密码生效。
如果重置密码的方式选择在线重置密码,请跳过该步骤。
单击试用实例的ID,选择安全组页签,单击安全组操作列的管理规则,在入方向添加需要放行的端口。本教程中,在安全组入方向放行SSH默认22端口和Apache默认80端口。
远程连接ECS实例。
返回实例页面,单击该实例对应操作列下的远程连接。
在弹出的连接与命令对话框中,单击通过Workbench远程连接对应的立即登录。
在弹出的登录实例对话框中,输入登录信息。
重复执行以上操作,登录ECS02实例。
步骤三:安装Nginx服务
执行命令安装Nginx。
sudo yum update && sudo yum -y install nginx
启动Nginx。
sudo systemctl start nginx
执行以下命令,查看Nginx服务的运行状态。
如果回显信息显示
Active:active(running)
时,表示Nginx已启动。systemctl status nginx
重复执行以上操作,在ECS02实例中安装Nginx服务。
步骤四:开发后端服务
创建服务目录。
sudo mkdir /data && cd /data
创建并编辑Python服务依赖文件。
sudo vim requirements.txt
进入Vim编辑器后,按
i
键进入编辑模式,粘贴以下内容。aliyun_python_sdk_core==2.13.36 aliyun_python_sdk_ecs==4.24.62 Flask==2.0.3
粘贴后,按Esc键,输入
:x
保存并退出编辑。执行如下命令安装依赖。
sudo pip3 install --upgrade pip && sudo pip3 install -r requirements.txt
创建并编辑Python服务代码文件。
sudo vim get_server_info.py
进入Vim编辑器后,按
i
键进入编辑模式,粘贴以下内容。说明代码中metaUrl中EcsRamRoleTest需要和前面创建的角色名称保持一致。
代码中region需要与您真实创建实例地域保持一致。
# -*- coding: utf-8 -*- from flask import Flask, jsonify, request from aliyunsdkcore.client import AcsClient from aliyunsdkcore.auth import credentials import requests import json from aliyunsdkecs.request.v20140526 import DescribeInstancesRequest, DescribeInstanceStatusRequest app = Flask(__name__) metaUrl = 'http://100.100.100.200/latest/meta-data/ram/security-credentials/EcsRamRoleTest' region = 'cn-beijing' # 获取临时身份凭证 def getStsToken(): tokenResponse = requests.get(metaUrl) return tokenResponse.json() # 用于健康检查 @app.route('/', methods=['HEAD', 'GET']) def index(): return "ok" # 在app.route装饰器中声明响应的URL和请求方法 @app.route('/ecs/getServerInfo', methods=['GET']) def getServerInfo(): tokenResult = getStsToken() accessKeyId = tokenResult['AccessKeyId'] accessSecret = tokenResult['AccessKeySecret'] securityToken = tokenResult['SecurityToken'] credential = credentials.StsTokenCredential(accessKeyId, accessSecret, securityToken) client = AcsClient(credential=credential, region_id=region) # GET方式获取请求参数 instanceId = request.args.get("instanceId") if instanceId is None: return "Invalid Parameter" # 查询实例信息 describeInstancesRequest = DescribeInstancesRequest.DescribeInstancesRequest() describeInstancesRequest.set_InstanceIds([instanceId]) describeInstancesResponse = client.do_action_with_exception(describeInstancesRequest) # 返回数据为bytes类型,需要将bytes类型转换为str然后反序列化为json对象 describeInstancesResponse = json.loads(str(describeInstancesResponse, 'utf-8')) print(describeInstancesResponse) if len(describeInstancesResponse['Instances']['Instance']) == 0: return jsonify({}) instanceInfo = describeInstancesResponse['Instances']['Instance'][0] # 查询实例状态 describeInstanceStatusRequest = DescribeInstanceStatusRequest.DescribeInstanceStatusRequest() describeInstanceStatusRequest.set_InstanceIds([instanceId]) describeInstanceStatusResponse = client.do_action_with_exception(describeInstanceStatusRequest) describeInstanceStatusResponse = json.loads(str(describeInstanceStatusResponse, 'utf-8')) instanceStatus = describeInstanceStatusResponse['InstanceStatuses']['InstanceStatus'][0]['Status'] # 封装结果 result = { # cpu数 'Cpu': instanceInfo['Cpu'], # 内存大小 'Memory': instanceInfo['Memory'], # 操作系统名称 'OSName': instanceInfo['OSName'], # 实例规格 'InstanceType': instanceInfo['InstanceType'], # 实例公网IP地址 'IpAddress': instanceInfo['PublicIpAddress']['IpAddress'][0], # 公网出带宽最大值 'InternetMaxBandwidthOut': instanceInfo['InternetMaxBandwidthOut'], # 实例状态 'instanceStatus': instanceStatus } return jsonify(result) if __name__ == "__main__": app.run()
粘贴后,按Esc键,输入
:x
保存并退出编辑。重复执行以上操作,在ECS02实例中开发后端服务。
步骤五:安装uWSGI Server
写完服务端代码后,您需要安装并使用uWSGI来启动Flask服务。
执行命令安装uWSGI。
sudo pip3 install uwsgi
新建uwsgi配置文件。
cd /data && sudo vim uwsgi.ini
进入Vim编辑器后,按
i
键进入编辑模式。[uwsgi] #uwsgi启动时所使用的地址和端口 socket=127.0.0.1:5000 #指向网站目录 chdir=/data #python启动程序文件 wsgi-file=get_server_info.py #python程序内用以启动的application变量名 callable=app #处理器数 processes=1 #线程数 threads=2 #状态检测地址 stats=127.0.0.1:9191 #保存启动之后主进程的pid pidfile=uwsgi.pid #设置uwsgi后台运行,uwsgi.log保存日志信息 自动生成 daemonize=uwsgi.log
粘贴后,按Esc键,输入
:x
保存并退出编辑。运行
which uwsgi
命令,查找并确认uwsgi
可执行文件的完整路径。系统返回信息如下:
/usr/local/bin/uwsgi
运行uwsgi server。
sudo /usr/local/bin/uwsgi uwsgi.ini
执行以下命令查看uwsgi服务启动情况,看到如下图效果是服务启动成。
ps aux | grep uwsgi
重复执行以上操作,在ECS02实例中安装uWSGI Server。
步骤六:配置Nginx并重启
启动好后端服务后,我们需要添加Nginx配置来代理后端服务。
创建配置文件。
sudo vim /etc/nginx/conf.d/app.conf
进入Vim编辑器后,按
i
键进入编辑模式。server { listen 80 default_server; server_name app.example.com; root /var/www/html; # Add index.php to the list if you are using PHP index index.html index.htm index.nginx-debian.html; location / { # 转发端口 uwsgi_pass 127.0.0.1:5000; include uwsgi_params; } }
粘贴后,按Esc键,输入
:x
保存并退出编辑。重启Nginx。
sudo nginx -s reload
验证配置是否成功。
说明如果未运行成功,可以在/data/uwsgi.log日志文件查看原因。
curl http://127.0.0.1/ecs/getServerInfo
命令执行结果是
Invalid Parameter
表示服务配置成功。重复执行以上操作,在ECS02实例中配置Nginx并重启。
步骤七:配置监听
负载均衡实例监听负责检查连接请求,然后根据调度算法定义的转发策略将请求流量分发至后端服务器。
在实例管理页面,单击已创建的CLB实例ID。
在监听页签单击添加监听。
在协议&监听配置向导,完成以下主要参数的配置,其余参数保持默认配置,然后单击下一步。
监听配置
说明
示例值
选择负载均衡协议
选择监听的协议类型。
HTTP
监听端口
设置前端协议端口,即用来接收请求并向后端服务器进行请求转发的监听端口。
监听端口范围:1~65535。
80
监听名称
自定义监听的名称。
HTTP_80
在后端服务器配置向导,选择默认服务器组,可以看到已添加的ECS01和ECS02,如果没默认添加点击继续添加,选择刚刚创建的ECS01和ECS02实例。
输入ECS01和ECS02的端口,本教程都设置为80,然后单击下一步。
在健康检查配置向导,保持默认配置,单击下一步,然后单击提交。等待配置成功后,单击知道了。
步骤三:注册微信小程序
在开发小程序之前,您需要先注册微信小程序。
步骤四:安装小程序开发环境并创建项目
启动好后端服务后,我们接下来要开发小程序。先安装小程序开发环境。
安装Node.js开发环境,请到Node.js页面下载并安装Node.js环境。
下载并安装微信小程序开发工具。详细信息请参见开发工具下载。
打开小程序开发工具,使用微信扫码登录。
单击加号创建微信小程序示例项目。
参考以下填写项目信息,最后单击新建。
项目名称:例如ECSAssistant。
目录:例如D:\workspace\wechat\ECSAssistant。
AppID:小程序的唯一标识,从小程序控制台获取。
开发模式:小程序。
后端服务:不使用云服务。
配置项目允许访问非HTTPS域名。在顶部配置栏,选择设置>项目设置,在本地设置页签,选中不校验合法域名、web-view(业务域名)、TLS版本一级HTTPS证书。
步骤五:开发小程序
安装好开发环境后,我们来编写小程序代码。
生成的小程序示例项目结构如下。
可以看到小程序的项目结构中有三种前缀为app的文件,它们定义了小程序的一些全局配置。
app.json应用配置。用于配置小程序的页面列表、默认窗口标题、导航栏背景色等。更多信息,请参见全局配置。
app.acss应用样式。定义了全局样式,作用于当前小程序的所有页面。
app.js应用逻辑。可配置小程序的生命周期,声明全局数据,调用丰富的API。
小程序所有的页面文件都在pages/路径下,页面文件有四种文件类型,分别是.js、.wxml、.wxss、和.json后缀的文件。相比全局配置文件,页面配置文件只对当前页面生效。其中.wxml文件定义了当前页面的页面结构。小程序中的所有页面都需要在app.json文件中声明。更多信息,请参见代码构成。
此外,项目顶层还有开发工具配置文件project.config.json和爬虫索引文件sitemap.json。
ECSAssistant ├── app.js ├── app.json ├── app.wxss ├── pages │ ├── index │ │ ├── index.js │ │ ├── index.json │ │ ├── index.wxml │ │ └── index.wxss │ └── logs │ ├── logs.js │ ├── logs.json │ ├── logs.wxml │ └── logs.wxss ├── project.config.json └── sitemap.json
编辑app.json文件,将小程序页面Title修改为ECS小助手,修改后的app.json文件内容如下。
{ "pages":[ "pages/index/index", "pages/logs/logs" ], "window":{ "backgroundTextStyle":"light", "navigationBarBackgroundColor": "#fff", "navigationBarTitleText": "ECS小助手", "navigationBarTextStyle":"black" }, "style": "v2", "sitemapLocation": "sitemap.json" }
编辑pages/index/index.wxss文件,定义index的页面样式,修改后的index.wxss文件内容如下。
.search-input { position: relative; margin-bottom: 50rpx; padding-left:80rpx; line-height: 70rpx; height: 80rpx; box-sizing: border-box; border: 2px solid #ff8f0e; border-radius: 100rpx; overflow: hidden; text-overflow: ellipsis; transition: border 0.2s; } .resultView { margin-top: 70rpx; } .result { position: relative; left: 30rpx; display: list-item; font-size: small; }
编辑pages/index/index.js文件,定义搜索框的失去焦点事件,修改后的index.js文件内容如下。
说明将代码中<CLB_PUBLIC_IP>换成您刚刚创建的CLB实例的公网IP。
Page({ data: { queryResult: null, showView: 'false', }, bindblur: function(e) { let that = this; wx.request({ url: 'http://<CLB_PUBLIC_IP>/ecs/getServerInfo', method: 'GET', data: { instanceId: e.detail.value }, success(res) { if(res.statusCode == 200){ that.setData({ queryResult: res.data, showView: !that.data.showView, }); }else{ that.setData({ showView: 'false', }); wx.showToast({ title: '请输入你的ECS实例ID', duration: 1500, icon: 'none', mask: true }) } } }) } })
编辑pages/index/index.wxml文件,编写展示界面,修改后的index.wxml文件内容如下。
<view class='container'> <input placeholder='请输入你的ECS实例ID' class='search-input' value='{{ inputValue }}' bindblur='bindblur'></input> <view class='resultView' hidden='{{ showView }}'> <text class='result'>CPU数:{{queryResult.Cpu}} 核</text> <text class='result'>内存大小:{{queryResult.Memory}} MB</text> <text class='result'>操作系统:{{queryResult.OSName}}</text> <text class='result'>实例规格:{{queryResult.InstanceType}}</text> <text class='result'>公网IP地址:{{queryResult.IpAddress}}</text> <text class='result'>网络带宽:{{queryResult.InternetMaxBandwidthOut}} MB/s</text> <text class='result'>在线状态:{{queryResult.instanceStatus == 'Running' ? '运行中':'已关机'}}</text> </view> </view>
保存后,编辑器会自动刷新。看到如下界面,表示小程序运行成功了。
步骤六:测试微信小程序
完成以上操作后,您已经成功部署了服务端程序,并且在本地开发好了小程序。
您可以登录ECS控制台,复制刚刚创建的ECS实例ID,输入到小程序输入框中,就可以看到结果了。
您可以通过停机一台ECS模拟故障从而验证服务的可用性。操作如下:
登录ECS控制台,找到目标实例,在操作列单击,在面板单击停止。
等ECS状态为已停止后,再次在小程序中查询ECS实例ID,看到返回正常内容,则表明服务可用。
小程序界面的示意图如下:
后续步骤
如果您期望上线您的小程序,您需要做下面几件事:
申请域名,可以参考通用域名注册基本流程如何注册阿里云域名。
申请SSL证书,并配置到服务器上,可以参考申请个人测试证书。
上传小程序并提交审核,可以参考小程序发布上线。
待审核通过后,手动上线小程序,就可以在微信客户端中查看和使用小程序了。