什么是 API 网关?
API 网关是一个扮演逻辑入口角色的服务,它主要负责对外提供服务 API,同时完成对请求进行管理、访问控制、响应合并、性能优化等多种功能。API 网关一般都是部署在云端,可以为服务提供统一的访问入口,同时将请求路由到后端服务提供者。
Serverless 技术背景
在 Serverless 技术背景下,开发人员不需要关心基础设施,更专注于应用程序的编写,而大多数云厂商都提供了相关的 Serverless 服务,如 AWS 的 Lambda,Azure 的 Functions 等等。尤其是 AWS 的 Lambda,通过使用它可以管理、运行和扩展代码,只需少量代码即可构建出强大的应用程序。利用 Serverless 技术可以提高应用程序的可靠性、弹性和可伸缩性。
PlusServerless-API 网关实践方案
PlusServerless-API 是一种 Serverless 技术实现的 API 网关方案,它可以很方便地配置和运行,同时可以自动缩放,无需管理不必要的基础设施。
实现步骤
步骤 1:创建 API Gateway
首先需要创建 API Gateway 对象。可以通过运行以下代码在 AWS Lambda 中创建一个 API Gateway:
const aws = require('aws-sdk'); const APIGateway = new aws.APIGateway(); // 创建或更新 API Gateway async function createOrUpdateApiGateway(apiGatewayConfig) { const {RestApiId: apiId, StageName: stage} = apiGatewayConfig; const response = await APIGateway.getResources({restApiId: apiId, limit: 500}).promise(); const resources = response.items || []; for (let i = 0, len = resources.length; i < len; i++) { const id = resources[i].id; if (id.startsWith('p_')) { await APIGateway.deleteResource({restApiId: apiId, resourceId: id}).promise(); } } return APIGateway.createResource(apiGatewayConfig).promise(); } // 部署 API Gateway async function deployApiGateway(apiGatewayConfig) { const {restApiId: restApiId, stageName: stageName} = apiGatewayConfig; await APIGateway.createDeployment({restApiId: restApiId, stageName: stageName}).promise(); }
步骤 2:创建 Lambda Function
创建 Lambda Function 非常简单,只需在 AWS Lambda 界面单击“创建函数”按钮,上传代码包到 Lambda 并为其指定适当的配置即可。调用 Lambda 时可以使用 API Gateway 触发器。
步骤 3:创建 Authorization Policy
创建授权策略包括这些步骤:
- 创建 IAM 角色并分派 API Gateway 授权。
// 创建角色 const createRole = require('./create-role'); async function createLambdaRole() { // 创建 Lambda角色 const role = await createRole('lambda-api-gateway-role', 'AssumeRolePolicyDocument.json'); // 向角色绑定 API Gateway 服务 const policy = new aws.IAM.Policy({ PolicyName: 'lambda-api-gateway-policy', PolicyDocument: { Version: '2012-10-17', Statement: [ { Effect: 'Allow', Action: [ 'logs:*', 'execute-api:*', ], Resource: '*', }, ], }, }); await policy.attachRole({ RoleName: role.Role.RoleName }).promise(); return role; }
- 在 API Gateway 中配置 OAuth2 授权模式。
async function enableOAuthLambdaIntegration(apiGatewayId, basePath, authorizerId) { const endpointUri = `arn:aws:apigateway:${AWS.config.region}:lambda:path/2015-03-31/functions/arn:aws:lambda:${AWS.config.region}:${APIGatewayLambdaRole.accountId}:function:${AuthorizerLambdaConfiguration.functionName}/invocations`; const integration = await APIGateway.putIntegration({ httpMethod: 'ANY', resourceId: rootResource.id, type: 'AWS_PROXY', integrationHttpMethod: 'POST', uri: endpointUri, integrationResponses: { 'default': { statusCode: 200, }, }, requestParameters: { 'integration.request.header.Content-Type': "'application/json'", }, }).promise(); const method = await APIGateway.putMethod({ httpMethod: 'ANY', resourceId: rootResource.id, restApiId: apiGatewayId, authorizationType: 'CUSTOM', authorizerId: authorizerId, requestParameters: { 'method.request.header.Accept': false, }, requestModels: { 'application/json': 'Empty', }, requestValidatorId: requestBodyValidator.id, }).promise(); }
步骤 4:绑定 Lambda Function 和 API Gateway
将使用者从 API Gateway 中删除并添加资源,然后添加相应的 Lambda 触发器。
// 绑定 Lambda 和 API Gateway const createApiGatewayResource = require('./create-api-gateway-resource'); const createApiGatewayMethod = require('./create-api-gateway-method'); async function createLambdaApi(api, stage, apiGatewayLambda) { // 删除使用者并添加资源 const rootResource = await deleteDefaultApiGateway(api.id); const resource = await createApiGatewayResource(resourcePath, api.id, rootResource); // 添加需要的方法,比如 GET, POST, PUT await Promise.all(methods.map((method) => createApiGatewayMethod(resource, api.id, method.method, apiGatewayLambda, method.validator, requestBodyValidator, responseBodyValidator, responseHeaderValidator))); // 部署 await deployApiGateway(apiGatewayConfig, api.id); }
示例代码
以下是一个具体的使用 PlusServerless-API 实现的 API 网关的示例代码。
const AWS = require('aws-sdk'); const accessKey = process.env.ACCESS_KEY; const secretKey = process.env.SECRET_KEY; const region = process.env.REGION; // 配置 SDK const configure = () => { AWS.config.update({ accessKeyId: accessKey, secretAccessKey: secretKey, region: region, }); APIGateway = new AWS.APIGateway({ region: region }); }; // 创建授权角色 const createRole = async () => { const createRoleParams = { AssumeRolePolicyDocument: { Version: '2012-10-17', Statement: [ { Sid: '', Effect: 'Allow', Principal: { Service: 'apigateway.amazonaws.com', }, Action: 'sts:AssumeRole', }, ], }, Path: '/', RoleName: 'api-gateway-read-only', }; try { const role = await new AWS.IAM().createRole(createRoleParams).promise(); console.log(role); return role.Role; } catch (err) { console.error(err); throw new Error(`Error creating IAM role ${createRoleParams.RoleName}: ${err}`); } }; // API Gateway Rollback Protection const rollbackProtection = async (apiId) => { try { // 开启回滚保护 await APIGateway.updateRestApi({ restApiId: apiId, patchOperations: [{ op: 'add', path: '/disableExecuteApiEndpoints', value: 'false' }], }).promise(); console.log('API Gateway Rollback Protection 成功启用!'); return true; } catch (err) { console.error(err); throw new Error(`Error enabling API Gateway rollback protection: ${err}`); } }; // 创建 API Gateway const createApiGateway = async (apiName) => { try { const createRestApiParams = { name: apiName, description: 'Serverless API Gateway', apiKeySource: 'HEADER', }; const api = await APIGateway.createRestApi(createRestApiParams).promise(); console.log(`API Gateway ${apiName} 创建成功!`); await rollbackProtection(api.id); return api; } catch (err) { console.error(err); throw new Error(`Error creating API Gateway: ${err}`); } }; // 创建资源 const createResource = async (apiGatewayId, parentId, pathPart) => { try { const params = { parentId, pathPart, restApiId: apiGatewayId, }; const resource = await APIGateway.createResource(params).promise(); console.log(`Resource: ${params.pathPart} 创建成功!`); return resource; } catch (error) { console.error(error); throw new Error(`Error creating API Gateway Resource: ${error}`); } }; // 创建 Lambda Function const createLambdaFunction = async (funcName, zipBuffer) => { try { const createParams = { FunctionName: funcName, Code: { ZipFile: zipBuffer, }, Handler: 'index.handler', Runtime: 'nodejs12.x', Role: 'ARN-Of-IAM-Role-With-Lambda-Permissions', }; const lambda = new AWS.Lambda(); const lambdaCreation = await lambda.createFunction(createParams).promise(); console.log(`创建 Lambda function: ${funcName}`); return lambdaCreation; } catch (error) { console.error(error); throw new Error(`Error creating Lambda Function: ${error}`); } }; // 绑定 Lambda 和 API Gateway const bindLambdaFunctionAndApi = async (apiKey, restApiId, resourceId, httpMethod) => { try { const { FunctionArn } = await createLambdaFunction; const createIntegrationParams = { credentials: '', integrationHttpMethod: 'POST', type: 'AWS_PROXY', uri: `arn:aws:apigateway:${AWS.config.region}:lambda:path/2015-03-31/functions/${FunctionArn}/invocations`, restApiId, resourceId, httpMethod, }; const integration = await APIGateway.putIntegration(createIntegrationParams).promise(); console.log(`Lambda function ${apiKey} 绑定成功!`); return integration; } catch (error) { console.error(error); throw new Error(`Error binding Lambda function and API Gateway: ${error}`); } }; // 部署 const deploy = async (restApiId, stageName) => { try { const deployParams = { restApiId: restApiId, stageName: stageName, variables: {}, }; const deployment = await APIGateway.createDeployment(deployParams).promise(); console.log('API Gateway 部署成功!'); return deployment; } catch (error) { console.error(error); throw new Error(`Error deploying API Gateway: ${error}`); } }; // 启动函数 const runFunc = async () => { configure(); // 配置 AWS SDK 环境 await createRole(); // 创建授权角色 const apiGateway = await createApiGateway('PlusServerless-API'); // 创建新的 API Gateway const resource = await createResource(apiGateway.id, apiGateway.rootResourceId, 'users'); // 创建资源 const lambda = await createLambdaFunction('PlusServerless-API', fs.readFileSync('index.zip')); // 创建 Lambda Function await bindLambdaFunctionAndApi('apikey', apiGateway.id, resource.id, 'POST'); // 绑定 Lambda 和 API Gateway await deploy(apiGateway.id, 'PROD'); // 部署 }; runFunc();
总结
通过使用 PlusServerless-API,开发人员可以轻松地创建自己的 API 网关实现方案而无需关心基础设施的管理。同时,PlusServerless-API 方案提供了多种安全性规范,可以实现授权策略。
总之,PlusServerless-API 可以为 Serverless 应用程序的开发和部署提供可靠、安全的 API 入口,从而帮助开发人员有效地管理和监视其云端资产。
来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/65a5d2c3add4f0e0ffe61482