Hello all,
I am encountering an issue where all response headers that I set in the Middleware work fine locally but are not included in the response after deployment to a Vercel environment.
Current Behavior
When running locally, I can see all headers added correctly. However, when deployed, some headers that are set using res.headers.set()
in the middleware do not appear in the final response.
Here is the code from my middleware:
import { NextResponse } from 'next/server';
import { NextRequest } from 'next/server';
import crypto from 'crypto';
import { Session } from './session'; // Assuming Session is imported from another module
export function middleware(request: NextRequest) {
const optimizelyCmsUrl = process.env.OPTIMIZELY_CMS_URL ?? '';
// Add CSP
const nonce = Buffer.from(crypto.randomUUID()).toString('base64');
const cspHeader = `
default-src 'self';
script-src 'self' 'nonce-${nonce}' 'strict-dynamic' ${optimizelyCmsUrl} 'unsafe-eval';
style-src 'self' 'unsafe-inline';
img-src 'self' ${optimizelyCmsUrl} blob: data:;
font-src 'self';
object-src 'none';
base-uri 'self';
form-action 'self' ${optimizelyCmsUrl};
frame-ancestors 'self' ${optimizelyCmsUrl} https://app-ocxcjomu1du97yp002.cms.optimizely.com;
upgrade-insecure-requests;
`;
// Replace newline characters and spaces
const contentSecurityPolicyHeaderValue = cspHeader.replace(/\s{2,}/g, ' ').trim();
console.log("Generated CSP Header:", contentSecurityPolicyHeaderValue);
// Create response with modified headers
const requestHeaders = new Headers(request.headers);
requestHeaders.set('x-nonce', nonce);
let response = NextResponse.next({
request: {
headers: requestHeaders,
},
});
// Clone the response to set headers correctly
response = new NextResponse(response.body, response);
// Add the CSP header to the response
response.headers.set('Content-Security-Policy', contentSecurityPolicyHeaderValue);
// Enable dev mode adjustments
const isDev = process.env.NODE_ENV !== 'production' || request.nextUrl.host.includes('localhost');
if (isDev) {
response.headers.set('X-Dev-Mode', 'true');
}
// Make sure we're always in English - multi language is not supported yet
if (!request.nextUrl.pathname.startsWith("/en")) {
const newUrl = request.nextUrl.clone();
newUrl.pathname = "/en" + newUrl.pathname;
return NextResponse.redirect(newUrl, {
status: isDev ? 307 : 308
});
}
// Assign a Visitor ID cookie, so we can identify and track individual visitors
const visitorId = Session.getOrCreateVisitorId(request);
Session.addVisitorId(response, visitorId);
return response;
}
Expected Behavior
I expect Vercel Edge to behave the same way as my local dev environment and apply all headers that are set in the middleware. Specifically, I would like the Content-Security-Policy
and other headers set in the response to be included when deployed to production.
Environment Info
- Deployment URL or Custom Domain: https://optimizely-saas-cms-visual-builder-n48d1c09t.vercel.app/en/savings
- Environment: Local (works as expected), Preview (issue exists), Production (issue exists)
- Project Framework: Next.js
- Build Settings:
- Framework Preset: Next.js
- Node/Runtime Version: Node 18
- Package Manager: npm
- Relevant Packages: next@14.2.4
Steps to Reproduce
- Add the above middleware to a Next.js application.
- Deploy the application to Vercel.
- Observe that headers set locally in dev mode are not present in the deployed version.
Any help or insight would be greatly appreciated. Has anyone encountered this behavior before or found a way to get the headers applied consistently in both environments?
Thanks in advance!