dougmoscrop / serverless-http

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

Serverless HTTP + NEXTjs with ALB not returning cookie #219

Closed bzzanui closed 2 years ago

bzzanui commented 2 years ago

Hope some one could help, recently working the project and when turning on the "Multi value headers" in the ALB target group the cookie is sending correctly but the HTML page headers are also mess up that HTML page become download page.

Here is server.js start page:

const next = require('next');
const { parse } = require('url');
const sls = require('serverless-http');

const app = next({
    dev: false
});

const binaryMimeTypes = [
    'application/javascript',
    'application/json',
    'application/octet-stream',
    'application/xml',
    'font/eot',
    'font/opentype',
    'font/otf',
    'image/jpeg',
    'image/png',
    'image/svg+xml',
    'text/comma-separated-values',
    'text/css',
    'text/html',
    'text/javascript',
    'text/plain',
    'text/text',
    'text/xml'
];
const handle = app.getRequestHandler()
const server = (req, res) => app.prepare().then(
    () => {
        const parsedUrl = parse(req.url, true)
        const { pathname } = parsedUrl
        if (pathname === '/sw.js' || /^\/(workbox|worker|fallback)-\w+\.js$/.test(pathname)) {
            //const filePath = join(__dirname, '.next', pathname)
            //console.log(`load file ${pathname} ${filePath}`)
            //app.serveStatic(req, res, filePath)
            // next can handle this
            handle(req, res, parsedUrl)
        } else {
            let ip = null;
            if (req.apiGateway.event.requestContext
                && req.apiGateway.event.requestContext.identity
                && req.apiGateway.event.requestContext.identity.sourceIp) {
                ip = req.apiGateway.event.requestContext.identity.sourceIp
            }
            if (ip) {
                req.headers['x-lambda-ip'] = ip;
            }
            handle(req, res, parsedUrl)
        }
    }
)

module.exports.handler = sls(server, {
    binary: binaryMimeTypes,
    request(request, event, context) {
        request.context = event.requestContext;
        request.body = event.body;
    }
});

I have to override the body as when using in ALB the body is not actually sending to NextJS API pages. Try to solve the cookie issue, but looks like there is some gap that Serverless HTTP might not support NextJS+ALB well

"serverless-http": "^2.7.0", "next": "^12.0.1", "next-pwa": "^5.4.0",

Thanks.

bzzanui commented 2 years ago

Finally I have fixed this issue by myself. as AWS ALB is expecting single value in headers object which means you could not pass string[] to the value Also I could not see much function being implemented to support the full conversion from Class Http.ServerResponse https://nodejs.org/api/http.html#class-httpserverresponse To AWS request response Object: https://docs.aws.amazon.com/lambda/latest/dg/services-alb.html

{
    "statusCode": 200,
    "statusDescription": "200 OK",
    "isBase64Encoded": False,
    "headers": {
        "Content-Type": "text/html"
    },
    "body": "<h1>Hello from Lambda!</h1>"
}

Lucky you still allow us to do the manually mapping ourself

const sls = require('serverless-http');
module.exports.handler = sls(server, {
    binary: binaryMimeTypes,
    request(request, event, context) {
        request.context = event.requestContext;
        request.body = event.body;
    },
    async response(response, event, context) {
        return new Promise(resolve => {
            response.headers['Access-Control-Allow-Credentials'] = true;
            const cookies = response.getHeader('set-cookie');
            if (cookies && cookies.length > 0) {
                console.log('cookies', cookies);
                response.cookies = cookies;
                //set the first cookie
                response.headers['set-cookie'] = cookies[0];
            }
            resolve();
        })
    }
});

Was hoping this library 0 config and use directly but still need to change a bit to do the transformation, this method works in ALB without multipleHeaderValue enable, as once enabled the headers field will be ignore then some page Content-Type will be incorrect, which means you need to do more mapping to copy all headers to multiple headers yourself. But all in all this library still works.

Hope this helps