Open1

API Gateway (HTTP API)+ Lambda (node-canvas)ハマりポイント達

Nobuyuki ItoNobuyuki Ito

忘れそうなのでとりあえずスクラップブックに。
node-canvasは2.8.0
lambdaはnode14.x

canvas2.8.0をlambdaで動かすまで

  • node-canvasはネイティブなライブラリを参照する。かつnpm i canvasする環境に応じてprebuildされたライブラリがnode_modules/canvas/build/Release に格納される(ので、linux環境(WSL環境でもよかった)でnpm i して、lambdaにdeployすれば動きそう・・・だが動かない。
    • どうやらこれは最新版のprebuildライブラリが、lambdaの実行環境のamazonlinux2のlibの配置や、バージョンがミスマッチなせい
    • よくある手法としてはバージョンを下げる or コピーをするようにnpmのスクリプトをハックして実行する、だがこれは悔しいので正面から解決してみた

dockerのamazonlinux2をpull、その中で作業

  • まずlib64/ から libblkid.so.1 libmount.so.1 libuuid.so.1 をnode_modules/canvas/build/Release にコピー
  • yumでビルド系のプログラムをinstall (make gcc wget zlib-dev あたり)
  • libpng1.6.37のソースコードを持ってきてビルド(これをしないと、zlibのバージョンが合わなくて動かない amazonlinux2で使われているzlibが古いのが問題なのだが、なんで古いままなんだろう・・・?)
  • ビルドしたlibpng16.so.16を node_modules/canvas/build/Releaseにコピー
  • libz.so.1もlib64/から一応上書き(これは必要か不明)

以上を入れたやつをlambda_layerにデプロイ

API Gateway (HTTP API)から結果をGET

https://aws.amazon.com/jp/blogs/news/handling-binary-data-using-amazon-api-gateway-http-apis/
HTTP APIでもバイナリが使える。
これもはまったので注意。
ポイントは

  1. base64Encodeが必要
  2. canvasでのbase64エンコードはちょっと癖がある
    の2点。

node-canvasの出力をbase64エンコード

canvas.toDataURL("image/png")の結果がbase64エンコードされている。
されているが、若干余分なデータ("data:image/png;base64, ")が先頭についてくる。
ので、

const dataRaw = canvas.toDataUrl("image/png")
const data = dataRaw.split(",")[1]
callback(
  null,
  {
    statusCode: 200,
    headers: {
      "Content-Type": "image/png"
    },
    isBase64Encoded: true,
    body: data
  }
)

てな感じで値を返せばOK.

ここまでやっておけば、特に設定をすることもなく、API Gatewayはバイナリを返してくれる。