Angular AWS 无服务器 lambda 上的 SSR returns 随机数和字符
Angular SSR on AWS serverless lambda returns random numbers and characters
我正在尝试使用无服务器和 lambda 将 Angular SSR 应用程序部署到 AWS。作为这方面的初学者,我正在使用 this starter project to do so. I did not change any of the code except changing the name of the project to "public". There is a dedicated section in the readme 来解释如何做到这一点(“查找并用您的项目名称替换单词“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 虽然我看到的是随机数字和字符(由于 Whosebug 的字符限制,我不得不截断它):
PCFET0NUWVBFIGh0bWw+PGh0bWwgbGFuZz0iZW4iPjxoZWFkPgogIDxtZXRhIGNoYXJzZXQ9InV0Zi04Ij4KICA8dGl0bGU+Tmd4U2VydmVybGVzc1N0YXJ0ZXI8L3RpdGxlPgogIDxiYXNlIGhyZWY9Ii8iPgogIDxtZXRhIG5hbWU9InZpZXdwb3J0IiBjb250ZW50PSJ3aWR0aD1kZXZpY2Utd2lkdGgsIGluaXRpYWwtc2NhbGU9MSI+CiAgPGxpbmsgcmVsPSJpY29uIiB0eXBlPSJpbWFnZS94LWljb24iIGhyZWY9ImZhdmljb24uaWNvIj4KPGxpbmsgcmVsPSJzdHlsZXNo
在我看来,似乎返回了一些错误的内容类型,但我无法真正理解它。
随机字符串是什么?
“随机数字和字符”实际上不是随机的,而是HTML页面的base64编码。如果您对响应进行 base64 解码,您将获得一个 HTML 页面。
为什么我得到的是 base64 编码?
module.exports.handler = serverlessExpress({
app,
binarySettings: {
isBinary: ({ headers }) => true,
contentTypes: [],
contentEncodings: [],
},
});
base64编码是由于binarySettings in lambda.js. From the binarySettings section in serverless-express README:
binarySettings
Determine if the response should be base64 encoded before being
returned to the event source, for example, when returning images or
compressed files. This is necessary due to API Gateway and other event
sources not being capable of handling binary responses directly. The
event source is then responsible for turning this back into a binary
format before being returned to the client.
By default, this is determined based on the content-encoding
and
content-type
headers returned by your application. If you need
additional control over this, you can specify binarySettings
.
{
binarySettings: {
isBinary: ({ headers }) => true,
contentTypes: ['image/*'],
contentEncodings: []
}
}
Any value you provide here should also be specified on API Gateway
API. In SAM, this looks like:
ExpressApi:
Type: AWS::Serverless::Api
Properties:
StageName: prod
BinaryMediaTypes: ['image/*']
为什么会有启用 base64 编码的选项?
base64 编码选项主要用于您通过 AWS API 网关发送二进制数据作为响应的场景(例如:图像、GZip 文件等)。为了使二进制内容正常工作,您需要以 base64 编码格式发送 AWS Lambda proxy integration:
的响应
To handle binary payloads for AWS Lambda proxy integrations, you must
base64-encode your function's response. You must also configure the
binaryMediaTypes for your API. Your API's binaryMediaTypes
configuration is a list of content types that your API treats as
binary data. Example binary media types include image/png or
application/octet-stream. You can use the wildcard character (*) to
cover multiple media types. For example, */* includes all content
types.
修复 Content-Type header(可选)
默认情况下,页面响应的 Content-Type
header 为 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'
我创建了一个 PR 禁用 base64 编码(选项 1)。
注意:我必须在浏览器中进行硬刷新才能在新部署后更正响应。
接受的答案似乎解决了我的问题,但结果是图像没有渲染。奇怪的是没有错误(状态代码 200),但他们不会出现。
This thread 引导我走向正确的方向:
我在 lambda.js
:
中再次添加了二进制设置
module.exports.handler = serverlessExpress({
app,
binarySettings: {
isBinary: ({ headers }) => true,
contentTypes: [],
contentEncodings: [],
},
});
之后我更改了 API 网关设置并在 Binary Media Types
中添加了 */*
。这成功了。
我正在尝试使用无服务器和 lambda 将 Angular SSR 应用程序部署到 AWS。作为这方面的初学者,我正在使用 this starter project to do so. I did not change any of the code except changing the name of the project to "public". There is a dedicated section in the readme 来解释如何做到这一点(“查找并用您的项目名称替换单词“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 虽然我看到的是随机数字和字符(由于 Whosebug 的字符限制,我不得不截断它):
PCFET0NUWVBFIGh0bWw+PGh0bWwgbGFuZz0iZW4iPjxoZWFkPgogIDxtZXRhIGNoYXJzZXQ9InV0Zi04Ij4KICA8dGl0bGU+Tmd4U2VydmVybGVzc1N0YXJ0ZXI8L3RpdGxlPgogIDxiYXNlIGhyZWY9Ii8iPgogIDxtZXRhIG5hbWU9InZpZXdwb3J0IiBjb250ZW50PSJ3aWR0aD1kZXZpY2Utd2lkdGgsIGluaXRpYWwtc2NhbGU9MSI+CiAgPGxpbmsgcmVsPSJpY29uIiB0eXBlPSJpbWFnZS94LWljb24iIGhyZWY9ImZhdmljb24uaWNvIj4KPGxpbmsgcmVsPSJzdHlsZXNo
在我看来,似乎返回了一些错误的内容类型,但我无法真正理解它。
随机字符串是什么?
“随机数字和字符”实际上不是随机的,而是HTML页面的base64编码。如果您对响应进行 base64 解码,您将获得一个 HTML 页面。
为什么我得到的是 base64 编码?
module.exports.handler = serverlessExpress({
app,
binarySettings: {
isBinary: ({ headers }) => true,
contentTypes: [],
contentEncodings: [],
},
});
base64编码是由于binarySettings in lambda.js. From the binarySettings section in serverless-express README:
binarySettings
Determine if the response should be base64 encoded before being returned to the event source, for example, when returning images or compressed files. This is necessary due to API Gateway and other event sources not being capable of handling binary responses directly. The event source is then responsible for turning this back into a binary format before being returned to the client.
By default, this is determined based on the
content-encoding
andcontent-type
headers returned by your application. If you need additional control over this, you can specifybinarySettings
.{ binarySettings: { isBinary: ({ headers }) => true, contentTypes: ['image/*'], contentEncodings: [] } }
Any value you provide here should also be specified on API Gateway API. In SAM, this looks like:
ExpressApi: Type: AWS::Serverless::Api Properties: StageName: prod BinaryMediaTypes: ['image/*']
为什么会有启用 base64 编码的选项?
base64 编码选项主要用于您通过 AWS API 网关发送二进制数据作为响应的场景(例如:图像、GZip 文件等)。为了使二进制内容正常工作,您需要以 base64 编码格式发送 AWS Lambda proxy integration:
的响应To handle binary payloads for AWS Lambda proxy integrations, you must base64-encode your function's response. You must also configure the binaryMediaTypes for your API. Your API's binaryMediaTypes configuration is a list of content types that your API treats as binary data. Example binary media types include image/png or application/octet-stream. You can use the wildcard character (*) to cover multiple media types. For example, */* includes all content types.
修复 Content-Type header(可选)
默认情况下,页面响应的 Content-Type
header 为 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'
我创建了一个 PR 禁用 base64 编码(选项 1)。
注意:我必须在浏览器中进行硬刷新才能在新部署后更正响应。
接受的答案似乎解决了我的问题,但结果是图像没有渲染。奇怪的是没有错误(状态代码 200),但他们不会出现。
This thread 引导我走向正确的方向:
我在 lambda.js
:
module.exports.handler = serverlessExpress({
app,
binarySettings: {
isBinary: ({ headers }) => true,
contentTypes: [],
contentEncodings: [],
},
});
之后我更改了 API 网关设置并在 Binary Media Types
中添加了 */*
。这成功了。