将 cookie 传递给 CloudFront 源但防止缓存 [英] Pass cookie to CloudFront origin but prevent from caching
问题描述
我在 Symfony Web 应用程序前面使用 CloudFront 作为缓存.为了根据用户角色(管理员、客户等)获取缓存,我在 Lambda@Edge 查看器请求触发器中生成了基于用户角色的哈希.我将该哈希作为请求标头作为 X-User-Context-Hash
传递给我的源.
I am using CloudFront as cache in front of my Symfony web application. To get a cache based on a user's role (admin, customer,...) I generate a user role based hash in a Lambda@Edge Viewer Request trigger. I pass that hash on as a request header to my origin as X-User-Context-Hash
.
我的问题是现在我需要将 PHPSESSID
cookie 传递到我的源以获得正确的缓存响应,但我不想基于 的值缓存PHPSESSID
.我只需要我的缓存响应基于 X-User-Context-Hash
的值而不是我的会话 cookie.
My problem is now that I need to pass the PHPSESSID
cookie on to my origin to get the right response for caching, but I do not want to base the cache on the value of PHPSESSID
. I do only need my cached response to be based on the value of X-User-Context-Hash
but not on my session cookie.
下图应该能详细解释我的问题
The image below should explain my problem in detail
有没有可能做到这一点?
Is there any possibility to accomplish that?
非常感谢您的帮助.
这是我的 Lambda@Edge 查看器请求触发器:
Here's my Lambda@Edge Viewer Request trigger:
'use strict';
function parseCookies(headers) {
const parsedCookie = {};
if (headers.cookie) {
console.log(`${headers.cookie[0].value}`);
headers.cookie[0].value.split(';').forEach((cookie) => {
if (cookie) {
const parts = cookie.split('=');
parsedCookie[parts[0].trim()] = parts[1].trim();
}
});
}
return parsedCookie;
}
exports.handler = (event, context, callback) => {
const request = event.Records[0].cf.request;
const headers = request.headers;
const https = require('https');
// Read session cookie
const parsedCookies = parseCookies(headers);
let cookie = '';
if (parsedCookies) {
if(parsedCookies['PHPSESSID']) {
cookie = `PHPSESSID=${parsedCookies['PHPSESSID']}`;
}
}
console.log(`Cookie: ${cookie}`);
// Send request to origin host at /_fos_user_context_hash
// passing the original session cookie
const options = {
hostname: `${request.headers.host[0].value}`,
port: 443,
path: '/_fos_user_context_hash',
method: 'HEAD',
headers: {
'Cookie': cookie,
'Accept': 'application/vnd.fos.user-context-hash',
'Vary' : 'Cookie'
}
};
const req = https.request(options, (res) => {
console.log('statusCode:', res.statusCode);
console.log('headers:', res.headers);
// Read the X-User-Context-Hash from the hash endpoint
const headerName = 'X-User-Context-Hash';
let hash = 'anonymous';
if (res.headers[headerName.toLowerCase()]) {
hash = res.headers[headerName.toLowerCase()];
}
// Append X-User-Context-Hash before passing request on to CF
request.headers[headerName.toLowerCase()] = [{ key: headerName, value: hash }];
callback(null, request);
}).on('error', (e) => {
console.error(e);
// Forward request anyway
callback(null, request);
});
req.end();
}
;
推荐答案
以下是我最终解决问题的方法:
Here's how I finally solved my problem:
我将行为配置为不将任何 cookie 转发到源,而是仅根据标头 Host
和 X-User-Context-Hash
进行缓存(参见屏幕截图).
I configured the behavior not to forward any cookies to the origin, but only cache based on the headers Host
and X-User-Context-Hash
(see screenshot).
下图解释了我的 lambda@edge 过程:
The following image explains my lambda@edge process:
- 在查看器请求"触发器中,我读取了名为
PHPSESSID
和REMEMBERME
的基于用户的 cookie,并通过X-Session-Cookies
标题打开. - 如果我的请求 url 与给定的
Host
和X-User-Context-Hash
标头匹配,则 Cloud-Front 返回缓存的项目并在此处停止. - 如果没有匹配项,则会触发源请求"触发器.当该事件触发时,自定义标头
X-Session-Cookies
可用.因此,我从X-Session-Cookies
标头中获取值并将request.headers.cookie
的值设置为该值.此步骤可确保在缓存页面之前将PHPSESSID
和REMEMBERME
cookie 都传递给源.
- In the "Viewer Request" trigger I read the user-based cookies named
PHPSESSID
andREMEMBERME
and pass those values via theX-Session-Cookies
header on. - If the there's a match for my request url and the given
Host
andX-User-Context-Hash
headers, Cloud-Front returns the cached item and stops here. - If there's no match the "Origin Request" trigger is fired. When that event fires the custom header
X-Session-Cookies
is available. So I take the value from theX-Session-Cookies
header and set the value ofrequest.headers.cookie
to that value. This step ensures that thePHPSESSID
andREMEMBERME
cookie are both passed to the origin before the page gets cached.
我的 Lambda@Edge 函数:
查看者请求触发器:
'use strict';
function parseCookies(headers) {
const parsedCookie = {};
if (headers.cookie) {
console.log(`${headers.cookie[0].value}`);
headers.cookie[0].value.split(';').forEach((cookie) => {
if (cookie) {
const parts = cookie.split('=');
parsedCookie[parts[0].trim()] = parts[1].trim();
}
});
}
return parsedCookie;
}
exports.handler = (event, context, callback) => {
const request = event.Records[0].cf.request;
const headers = request.headers;
const https = require('https');
let sessionId = '';
// Read session cookie
const parsedCookies = parseCookies(headers);
let cookie = '';
if (parsedCookies) {
if(parsedCookies['PHPSESSID']) {
cookie = `PHPSESSID=${parsedCookies['PHPSESSID']}`;
}
if(parsedCookies['REMEMBERME']) {
if (cookie.length > 0) {
cookie += ';';
}
cookie += `REMEMBERME=${parsedCookies['REMEMBERME']}`;
}
}
console.log(`Cookie: ${cookie}`);
// Send request to origin host at /_fos_user_context_hash
// passing the original session cookie
const options = {
hostname: `${request.headers.host[0].value}`,
port: 443,
path: '/_fos_user_context_hash',
method: 'HEAD',
headers: {
'Cookie': cookie,
'Accept': 'application/vnd.fos.user-context-hash',
'Vary' : 'Cookie'
}
};
const req = https.request(options, (res) => {
console.log('statusCode:', res.statusCode);
console.log('headers:', res.headers);
// Read the X-User-Context-Hash from the hash endpoint
const headerName = 'X-User-Context-Hash';
let hash = 'anonymous';
if (res.headers[headerName.toLowerCase()]) {
hash = res.headers[headerName.toLowerCase()];
}
// Append X-User-Context-Hash before passing request on to CF
request.headers[headerName.toLowerCase()] = [{ key: headerName, value: hash }];
const sessionHeaderName = 'X-Session-Cookies';
request.headers[sessionHeaderName.toLowerCase()] = [{ key: sessionHeaderName, value: cookie }];
callback(null, request);
}).on('error', (e) => {
console.error(e);
// Forward request anyway
callback(null, request);
});
req.end();
}
;
源请求触发器:
exports.handler = (event, context, callback) => {
const request = event.Records[0].cf.request;
const sessionHeaderName = 'X-Session-Cookies';
let cookie = '';
if (request.headers[sessionHeaderName.toLowerCase()]) {
console.log(request.headers[sessionHeaderName.toLowerCase()]);
cookie = request.headers[sessionHeaderName.toLowerCase()][0].value;
}
request.headers.cookie = [{ key : 'Cookie', value : cookie }];
callback(null, request);
};
这篇关于将 cookie 传递给 CloudFront 源但防止缓存的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!