我正在尝试使用无服务器和lambda将Angular SSR应用程序部署到AWS。作为一个完全的初学者,我使用这个入门项目来做到这一点。我没有更改任何代码,只是将项目名称更改为";公开";。自述文件中有一个专门的部分解释了如何做到这一点("查找并将单词"ngx serverless starter"替换为您的项目名称"(。
之后,我将该项目上传到AWS。这是日志:
Serverless: Stack update finished...
Service Information
service: public
stage: dev
region: us-east-1
stack: public-dev
resources: 12
api keys:
None
endpoints:
GET - https://u3vc0nd65k.execute-api.us-east-1.amazonaws.com/dev
GET - https://u3vc0nd65k.execute-api.us-east-1.amazonaws.com/dev/{proxy+}
functions:
api: public-dev-api
layers:
None
所以我认为它有效。如果我点击提供的URL,尽管我看到了随机数字和字符(由于堆栈溢出的字符限制,我不得不将其截断(:
PCFET0NUWVBFIGh0bWw+PGh0bWwgbGFuZz0iZW4iPjxoZWFkPgogIDxtZXRhIGNoYXJzZXQ9InV0Zi04Ij4KICA8dGl0bGU+Tmd4U2VydmVybGVzc1N0YXJ0ZXI8L3RpdGxlPgogIDxiYXNlIGhyZWY9Ii8iPgogIDxtZXRhIG5hbWU9InZpZXdwb3J0IiBjb250ZW50PSJ3aWR0aD1kZXZpY2Utd2lkdGgsIGluaXRpYWwtc2NhbGU9MSI+CiAgPGxpbmsgcmVsPSJpY29uIiB0eXBlPSJpbWFnZS94LWljb24iIGhyZWY9ImZhdmljb24uaWNvIj4KPGxpbmsgcmVsPSJzdHlsZXNo
在我看来,可能有一些错误的内容类型被返回,但我真的无法理解
什么是随机字符串
";随机数和字符";实际上不是随机的,而是HTML页面的base64编码。如果你对响应进行base64解码,你会得到一个HTML页面。
为什么我要使用base64编码
module.exports.handler = serverlessExpress({
app,
binarySettings: {
isBinary: ({ headers }) => true,
contentTypes: [],
contentEncodings: [],
},
});
base64编码是由lambda.js中的binarySettings引起的
二进制设置
确定响应在被返回到事件源,例如,当返回图像或压缩文件。由于API网关和其他事件,这是必要的源不能直接处理二进制响应。这个事件源负责将其转换回二进制文件格式,然后返回给客户端。
默认情况下,这是基于
content-encoding
和应用程序返回的content-type
标头。如果您需要可以指定binarySettings
作为对此的附加控制。{ binarySettings: { isBinary: ({ headers }) => true, contentTypes: ['image/*'], contentEncodings: [] } }
您在此处提供的任何值也应在API网关上指定API在SAM中,这看起来像:
ExpressApi: Type: AWS::Serverless::Api Properties: StageName: prod BinaryMediaTypes: ['image/*']
为什么有启用base64编码的选项
base64编码选项主要用于通过AWS API网关发送二进制数据作为响应的场景(例如:图像、GZip文件等(。为了使二进制内容正常工作,您需要以base64编码格式发送响应以进行AWS Lambda代理集成:
要为AWS Lambda代理集成处理二进制有效载荷,您必须base64对函数的响应进行编码。您还必须配置API的二进制媒体类型。API的二进制媒体类型配置是API将其视为的内容类型的列表二进制数据。示例二进制媒体类型包括image/png或应用程序/八位字节流。您可以使用通配符(*(涵盖多种媒体类型。例如,*/*包括所有内容类型。
修复内容类型标头(可选(
默认情况下,页面响应的Content-Type
标头为application/json
。您可以在server.ts
和serverless.ts
中将其更改为text/html
。这并不是解决问题所必需的,但最好配置正确的Content-Type
。
// All regular routes use the Universal engine
server.get('*', (req, res) => {
res.header('Content-Type', 'text/html');
res.render(indexHtml, { req, providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }] });
});
选项1:禁用响应的base64编码
在lambda.js
中注释掉binarySettings
,使响应不是base64编码的。
module.exports.handler = serverlessExpress({
app,
// binarySettings: {
// isBinary: ({ headers }) => true,
// contentTypes: [],
// contentEncodings: [],
// },
});
选项2:使用API网关转换base64响应
如果在API网关中设置binaryMediaTypes
,它将自动将base64编码转换为正确的响应。如果在可选步骤中未更改Content-Type
,请使用application/json
。
provider:
name: aws
runtime: nodejs12.x
lambdaHashingVersion: 20201221
memorySize: 192
timeout: 10
apiGateway:
binaryMediaTypes:
- 'text/html'
我创建了一个禁用base64编码的PR(选项1(。
注意:在新部署后,我不得不在浏览器中进行硬刷新以更正响应。
接受的答案似乎解决了我的问题,但结果是图像没有渲染。奇怪的是,没有错误(状态代码200(,但它们不会出现。
这条线索把我引向了正确的方向:
我在lambda.js
:中再次添加了二进制设置
module.exports.handler = serverlessExpress({
app,
binarySettings: {
isBinary: ({ headers }) => true,
contentTypes: [],
contentEncodings: [],
},
});
之后,我更改了API网关设置,并在Binary Media Types
中添加了*/*
。这就成功了。