1. 介绍
本指南将介绍一种新的设计模式:基于事件的实时数据处理。为了更形象地描述,我们以图片分类为例,先介绍通过APIG触发器如何构建一个图片分类的Web应用,再介绍通过OBS触发器如何构造一个实时的图片分类系统。
这里再次强调下无服务器架构相比于传统的架构,具有如下优点:
- 无需关注任何服务器,只需关注核心业务逻辑,提高开发和运维效率
- 事件触发,灵活扩展
- 函数运行随业务量弹性伸缩,按需付费,执行才计费,对于负载波峰波谷非常明显的场景可以减少大量成本
- 通过简单的配置即可连通函数工作流和其它各云服务,甚至云服务和云服务
我们可以通过函数工作流服务来快速构建这个系统,并且完全无需关注服务器,且弹性伸缩运行、按需计费,如图:

3. 创建函数,使用空白模版
- 函数名称:
{任意字母或数字}
- 委托名称:
{准备工作中创建的委托}
- 函数执行入口:
index.handler
- 运行时语言:
Node.js 8.10
- 代码在线编辑输入下面代码,之后创建函数
图片分类系统业务代码 Image-Recognition.txt
Copied!
const https = require('https');
let CONTEXT = null;
exports.handler = async (event, context) => {
if (event.httpMethod === "OPTIONS") {
console.log('OPTIONS request, pass.');
const result = constructResponse('', 200);
return result;
}
CONTEXT = context;
const response = {
tags: []
};
let resError = '';
const tagNames = await tagImage(event).catch((error) => {
console.log(error);
resError = error;
});
if (tagNames) {
response.tags = tagNames;
return constructResponse(response, 200);
} else {
return constructResponse(resError, 500);
}
}
function tagImage(event) {
return new Promise((resolve, reject) => {
const payload = constructPayload(event);
const token = CONTEXT.getToken();
if (!token) {
reject('Can\'t get token, please set agency with IAM ');
}
const options = {
hostname: 'image.cn-north-1.myhuaweicloud.com',
port: 443,
path: '/v1.0/image/tagging',
method: 'POST',
headers: {
'Content-Type': 'application/json;charset=utf8',
'X-Auth-Token': token
}
};
const req = https.request(options, (res) => {
const status = res.statusCode;
console.log("tag request status:", status);
res.on('data', (data) => {
const dataObject = JSON.parse(data.toString());
console.log('tag result:', dataObject);
if (status === 200) {
const tags = dataObject.result.tags || [];
const tagNames = tags.map(item => item.tag.replace(' ', ''));
resolve(tagNames);
} else {
reject(dataObject);
}
});
});
req.on('error', (e) => {
reject(e);
});
req.write(JSON.stringify(payload));
req.end();
});
}
function constructResponse(data = '', code = 200) {
return {
body: typeof data === 'object' ? JSON.stringify(data) : (data + ''),
headers: {
"Content-Type":"application/json",
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "Content-Type,Accept",
"Access-Control-Allow-Methods": "GET,POST,PUT,DELETE"
},
statusCode: code,
isBase64Encoded: false
};
}
function constructPayload(event) {
if (event.httpMethod != "POST") {
return {
"image": "",
"url": "https://bjbucket.obs.myhwclouds.com/70923411.jpg"
}
}
const bodyStr = new Buffer(event.body, 'base64').toString('utf8');
let body = {};
try {
body = JSON.parse(bodyStr);
} catch(ex) { }
const payload = {
image: '',
url: '',
language: 'zh',
limit: '10',
threshold: CONTEXT.getUserData('THRESHOLD') || 50
}
if (body.image && body.image.trim && body.image.trim()) {
payload.image = body.image.trim();
} else {
payload.url = body.url || '';
}
return payload;
}
5. 创建前端页面函数。
- 函数名称:
{任意字母或数字}
- 委托名称:
{准备工作中创建的委托}
- 函数执行入口:
index.handler
- 运行时语言:
Node.js 6.10
- 代码在线编辑输入下面代码,之后创建函数
图片分类系统业务代码 Image-Recognition.txt
Copied!
const _ = require('lodash');
exports.handler = function(event, context, callback) {
const proto = event.headers['x-forwarded-proto'] || 'http';
const restApi = context.getUserData('REST_API');
if (!restApi) {
console.log('ERROR: please set REST_API for the function.');
const result = constructResponse('please set REST_API for your web.', {}, 400);
callback(null, result);
return;
}
const webUrl = `${proto}://fgs-image-tag-app.obs-website.cn-north-1.myhwclouds.com/?rest-api-tag=${restApi}#/image-tag`;
const result = constructResponse('', {
Location: webUrl
}, 302);
console.log(`Access web, and rest api is ${restApi}, redirect to ${webUrl}`);
callback(null, result);
}
function constructResponse(data = '', headers = {}, code = 200) {
return {
body: typeof data === 'object' ? JSON.stringify(data) : (data + ''),
headers: _.merge({
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Headers": "Content-Type,Accept",
"Access-Control-Allow-Methods": "GET,POST,PUT,DELETE"
}, headers),
statusCode: code,
isBase64Encoded: false
};
}
1. 介绍
本指南将介绍一种新的设计模式:基于事件的实时数据处理。为了更形象地描述,我们以图片分类为例,先介绍通过APIG触发器如何构建一个图片分类的Web应用,再介绍通过OBS触发器如何构造一个实时的图片分类系统。 这里再次强调下无服务器架构相比于传统的架构,具有如下优点:
我们可以通过函数工作流服务来快速构建这个系统,并且完全无需关注服务器,且弹性伸缩运行、按需计费,如图:
2. 准备工作
创建华为云账号并完成实名。
申请开通华为云图片检测服务的图片标签功能,开通后便可以调用图片标签接口了。
需要为当前函数设置委托,您需要将委托设置具有访问IAM的权限。
云服务
函数工作流 FunctionGraph
FunctionGraph Administrator
3. 创建函数,使用空白模版
{任意字母或数字}
{准备工作中创建的委托}
index.handler
Node.js 8.10
图片分类系统业务代码 Image-Recognition.txt
/** * This function is used to build a web application backend system for tagging images. * The function invokes the image tagging interface of the Image Recognition service to tag images, and provides an HTTP(S) API through an APIG trigger. * The body structure of a POST message for requesting the API is as follows: * { * image: 'Base64 code of an image' * } * The response body is as follows: * {"tags":["Park","Green","Human","Happy","Casual","Trees","Summer","Outdoor","Smile"]} * * Procedure: * 1. Create a function and an APIG trigger. Configure the None security authentication mode for the trigger in the test phase. * 2. After creating the function, specify an agency with IAM access permissions on the Configuration tab page, and apply for the Image Tagging function on the Image Recognition console. * 3. Use a tool such as Postman to call the URL of the APIG trigger by sending a POST request. Specify the Base64 code of an image in the request body. * * You can combine this template with the image-tag-app-web template to build a complete serverless image tagging web application. */ const https = require('https'); let CONTEXT = null; exports.handler = async (event, context) => { //Cross-origin verification if (event.httpMethod === "OPTIONS") { console.log('OPTIONS request, pass.'); const result = constructResponse('', 200); return result; } CONTEXT = context; const response = { tags: [] }; let resError = ''; const tagNames = await tagImage(event).catch((error) => { console.log(error); resError = error; }); if (tagNames) { response.tags = tagNames; return constructResponse(response, 200); } else { return constructResponse(resError, 500); } } function tagImage(event) { return new Promise((resolve, reject) => { const payload = constructPayload(event); const token = CONTEXT.getToken(); if (!token) { reject('Can\'t get token, please set agency with IAM '); } const options = { hostname: 'image.cn-north-1.myhuaweicloud.com', port: 443, path: '/v1.0/image/tagging', method: 'POST', headers: { 'Content-Type': 'application/json;charset=utf8', 'X-Auth-Token': token } }; const req = https.request(options, (res) => { const status = res.statusCode; console.log("tag request status:", status); res.on('data', (data) => { const dataObject = JSON.parse(data.toString()); console.log('tag result:', dataObject); if (status === 200) { const tags = dataObject.result.tags || []; const tagNames = tags.map(item => item.tag.replace(' ', '')); resolve(tagNames); } else { reject(dataObject); } }); }); req.on('error', (e) => { reject(e); }); req.write(JSON.stringify(payload)); req.end(); }); } function constructResponse(data = '', code = 200) { return { body: typeof data === 'object' ? JSON.stringify(data) : (data + ''), headers: { "Content-Type":"application/json", "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Headers": "Content-Type,Accept", "Access-Control-Allow-Methods": "GET,POST,PUT,DELETE" }, statusCode: code, isBase64Encoded: false }; } function constructPayload(event) { if (event.httpMethod != "POST") { return { "image": "", "url": "https://bjbucket.obs.myhwclouds.com/70923411.jpg" } } const bodyStr = new Buffer(event.body, 'base64').toString('utf8'); let body = {}; try { body = JSON.parse(bodyStr); } catch(ex) { } const payload = { image: '', url: '', language: 'zh', limit: '10', threshold: CONTEXT.getUserData('THRESHOLD') || 50 } if (body.image && body.image.trim && body.image.trim()) { payload.image = body.image.trim(); } else { payload.url = body.url || ''; } return payload; }
4. 在函数中创建触发器
API Gateway服务(APIG)
NONE
HTTPS
5000
创建后获得调用URL:
https://d7b17f433f48410381181bb1d678a833.apigw.cn-north-1.huaweicloud.com/picid
5. 创建前端页面函数。
{任意字母或数字}
{准备工作中创建的委托}
index.handler
Node.js 6.10
图片分类系统业务代码 Image-Recognition.txt
/** * This function is used to build a web application frontend system for tagging images. * With the access URL of an APIG trigger, the function redirects requests to a deployed web page. * The environment variable REST_API specifies the address of the image tagging API provided by the backend system. * * You can combine this template with the image-tag-app template to build a complete serverless image tagging web application. */ const _ = require('lodash'); exports.handler = function(event, context, callback) { // Access Web const proto = event.headers['x-forwarded-proto'] || 'http'; const restApi = context.getUserData('REST_API'); if (!restApi) { console.log('ERROR: please set REST_API for the function.'); const result = constructResponse('please set REST_API for your web.', {}, 400); callback(null, result); return; } const webUrl = `${proto}://fgs-image-tag-app.obs-website.cn-north-1.myhwclouds.com/?rest-api-tag=${restApi}#/image-tag`; const result = constructResponse('', { Location: webUrl }, 302); console.log(`Access web, and rest api is ${restApi}, redirect to ${webUrl}`); callback(null, result); } function constructResponse(data = '', headers = {}, code = 200) { return { body: typeof data === 'object' ? JSON.stringify(data) : (data + ''), headers: _.merge({ "Content-Type": "application/json", "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Headers": "Content-Type,Accept", "Access-Control-Allow-Methods": "GET,POST,PUT,DELETE" }, headers), statusCode: code, isBase64Encoded: false }; }
6. 在函数中添加环境变量
REST_API
https://d7b17f433f48410381181bb1d678a833.apigw.cn-north-1.huaweicloud.com/picid
7. 在函数中创建触发器
API Gateway服务(APIG)
NONE
HTTPS
5000
8.(可选): 通过在OBS上传代码包构建前端Web
9. 恭喜你
你已经开发完了一个实时的图片分类系统。 访问前端:
https://d7b17f433f48410381181bb1d678a833.apigw.cn-north-1.huaweicloud.com/picidweb
你已经成功完成了Codelab并学到了: