dougmoscrop / serverless-http

Use your existing middleware framework (e.g. Express, Koa) in AWS Lambda 🎉
Other
1.72k stars 165 forks source link

Binary body results in broken images #163

Closed tyrauber closed 4 years ago

tyrauber commented 4 years ago

I am attempting to load serverless-sharp as serverless-http koa middleware, but having some difficulty with binary conversion resulting in broken images. My understanding based on reading previous issues (#52,#88) is that serverless-http automatically converts to binary given the appropriate file type. This, I believe, might be resulting in double encoding.

serverless-sharp is converting the image body to a buffer binary Buffer.from(originalImageBody, 'binary') and returning a base64 encoded string bufferImage.toString('base64').

The appropriate content type is set, the body payload is binary and the content length indicates the content is present, but the image returned is broken. The content length is increased compared to content served by the handler directly which makes me believe serverless-http might be re-encoding binary as binary? Or doing some additional body modification?

I've tried setting the { binary: ['image/*'] } to the serverless-http handler with the same result.

module.exports.handler = serverless(app, { binary: ['image/*'] });

Here is some example middleware:

const serverless = require('serverless-http');
const Koa = require('koa');
const { handler } = require(‘./node_modules/serverless-sharp/src/index')

const app = new Koa();

app.use(async(ctx,next) => {
  const event = {
    path: ctx.path,
    headers: ctx.header,
    queryStringParameters: {...ctx.request.query},
    status: 200
  }
  const succeed  = (result) => {
    ctx.set(result.headers)
    ctx.status = result.statusCode
    ctx.body = result.body
  }
  await handler(event, { succeed: succeed })
});

module.exports.handler = serverless(app);

Any insight or suggestions?

tyrauber commented 4 years ago

Ok. Even simpler example of the issue with just serverless-http and koa, based on the original API Gateway Binary Support example.

There is some issue between serverless-http and koa in regards to binary content that I am missing here.

Edit: Ok. I got it. Koa wants a Buffer for the body, not a base64 string. This works:

handler.js

const fs = require('fs')
const serverless = require('serverless-http');
const Koa = require('koa');
const app = new Koa();

app.use(async(ctx,next) => {
  let body = new Buffer(fs.readFileSync('public/logo.png'))
  ctx.set({
    "Content-Type": "image/png",
    "Access-Control-Allow-Origin" : "*", // Required for CORS support to work
    "Access-Control-Allow-Credentials" : true // Required for cookies, authorization headers with HTTPS
  })
  ctx.status = 200
  ctx.body = body
  await next();
})

module.exports.handler = serverless(app, { binary: ['*/*'] });

serverless.yml

service: test

provider:
  name: aws
  runtime: nodejs12.x
  apiGateway:
    binaryMediaTypes:
      - '*/*'

functions:
  image:
    handler: handler.handler
    events:
      - http:
          method: GET
          path: /{any+}
          cors: true
custom:
  serverless-offline:
    noPrependStageInUrl: true
plugins:
  - serverless-offline