Cloudfront Lambda @ Edge устанавливает cookie по запросу зрителя - PullRequest
0 голосов
/ 12 марта 2019

Обновление: лучше собрал мои мысли

Я генерирую уникальный идентификатор (UUID) для каждого пользователя в лямбда-запросе Viewer, а затем выбираю кэшированную страницу для возврата на основе этого UUID. Это работает.

В идеале у этого пользователя всегда должен быть один и тот же UUID.

Я должен сгенерировать этот UUID в запросе Viewer , если его нет в файле cookie в этом запросе Viewer. Мне также нужно, чтобы UUID был установлен как cookie, что, конечно, происходит в ответе, а не в запросе.

Без кэширования мой сервер просто обрабатывает получение пользовательского заголовка и создание Set-Cookie в заголовке ответа.

Я не нахожу способ справиться с этим, если я хочу кэшировать страницу. Я могу проигнорировать заголовок запроса для кэширования и предоставить правильную кэшированную страницу, но тогда пользователь не сохранит этот UUID, поскольку в следующем запросе не задано использование файла cookie.

Кто-нибудь достиг такого?

Вещи, которые я пытаюсь

Есть несколько аспектов, над которыми я работаю, но пока не смог приступить к работе:

  1. Какой-то параметр в Cloudfront, о котором я не знаю, который обрабатывает заголовок или другие данные, передаваемые из Viewer Request в Viewer Response, которые могут использоваться во второй лямбде в Cloudfront.

  2. Преимущественно изменить заголовки объекта ответа в запросе средства просмотра. Я не думаю, что это возможно, поскольку они возвращают заголовки, которые еще не созданы, если только я не пропустил какую-то встроенную методологию Cloudfront.

  3. Существующий сквозной заголовок какого-то рода, я не знаю, является ли это вообще чем-то, поскольку я не очень хорошо знаком с этим аспектом обработки запроса-ответа, но стоит попробовать.

  4. Возможно (еще не пытался) я мог бы создать весь объект ответа в лямбда-запросе клиента и каким-то образом обслуживать оттуда кэшированную страницу, модифицируя заголовки ответа и передавая ее в метод обратного вызова.

Ответ Тобина на самом деле работает, но не является твердым решением. Если пользователь не хранит и не обслуживает свои куки, это становится бесконечным циклом, плюс я бы не стал создавать перенаправление перед всеми моими страницами, если смогу избежать этого


Несколько работающая концепция

  1. Запрос Viewer Lambda, когда UUID отсутствует в файлах cookie, генерирует UUID
  2. Запрос Viewer Lambda устанавливает UUID в куки на заголовок в объекте запроса. Обратный вызов с обновленным объектом запроса передан в
  3. Наличие UUID-файлов cookie. Кэш Cloudfront
  4. Запрос на отправку лямбда запускается при наличии UUID
  5. Исходный запрос Lambda снова вызывает URL исходного запроса через http.get с установленным UUID cookie (ограничение в 40 КБ делает это невозможным в Viewer Request Lambda)
  6. Второй сценарий для Viewer Request Lambda, видя, что UUID теперь присутствует, удаляет UUID cookie, затем продолжает запрос в обычном режиме
  7. Второй запрос источника, если он еще не кэширован - Кэшированный ответ, если он кэширован, так как UUID очистки кеша отсутствует - возвращает фактический HTML-код страницы в запрос первого источника
  8. First Origin Request получает ответ от http.get, содержащий HTML
  9. First Origin Request создает пользовательский объект ответа, содержащий тело ответа из http.get и заголовок Set-Cookie, установленный с нашим исходным UUID

Последующие вызовы, у которых уже установлен UUID, уберут UUID из файла cookie (чтобы предотвратить разрушение кэша) и перейдут непосредственно ко второму сценарию в лямбда-запросе Viewer, который непосредственно загрузит кэшированную версию страницы.

Я говорю «несколько», потому что, когда я пытаюсь достичь своей конечной точки, я получаю загруженный двоичный файл.

РЕДАКТИРОВАТЬ

Это потому, что я не устанавливал заголовок content-type. У меня сейчас только 302 проблема с перенаправлением ... если я преодолею это, я выложу полный ответ.


Оригинальный вопрос

У меня есть функция запроса Viewer, которая выбирает опцию и устанавливает некоторые вещи в запросе, прежде чем он будет извлечен из кэша или сервера.

Это работает, но я хочу, чтобы он запомнил этот выбор для будущих пользователей. Идея состоит в том, чтобы просто установить cookie-файл, который я смогу прочитать при следующем входе пользователя. Поскольку это по запросу зрителя, а не по ответу зрителя, я не выяснил, как это сделать, или возможно ли это даже через саму лямбду.

Viewer Request -> 
  Lambda picks options (needs to set cookie) -> 
    gets corresponding content -> 
      returns to Viewer with set-cookie header intact

Я видел примеры и смог успешно установить файлы cookie в ответе Viewer через лямбду. Это не очень помогает мне, так как решение должно быть принято по запросу. Неудивительно, что добавление этого кода в запрос средства просмотра ничего не показывает в ответе.

Ответы [ 2 ]

2 голосов
/ 31 марта 2019

Я бы сказал, что действительно правильный способ установить несуществующий файл cookie - это вернуть перенаправление 302 на тот же URI с Set-Cookie и позволить браузеру повторить запрос.Это, вероятно, не окажет большого влияния, так как браузер может повторно использовать то же соединение, чтобы «следовать» за перенаправлением.

Но если вы настаиваете на том, чтобы не делать это таким образом, вы можете вставить cookie в запросс помощью триггера Viewer Request и затем отправьте Set-Cookie с тем же значением в триггере Viewer Response.

Объект request , в событии Viewer response ,может быть найден там же, где и в исходном событии request , event.Records[0].cf.request.

В триггере ответа зрителя эта часть структуры содержит запрос ", который CloudFront получил от зрителя и который мог быть изменен функцией Lambda, которая была запущена зрителемсобытие запроса. "

Будьте осторожны, чтобы правильно обрабатывать заголовок файла cookie.Cookie заголовок запроса требует осторожных и точных манипуляций, поскольку браузер может использовать несколько форматов при наличии нескольких файлов cookie.

Когда-то файлы cookie требовались дляотправлять как один заголовок запроса.

Cookie: foo=bar; buzz=fizz

Разобрать их, разделив значения на ;, а затем <space>.

Но браузер также может разделить их с несколькими заголовками,например:

Cookie: foo=bar
Cookie: buzz=fizz

В последнем случае массив event.Records[0].cf.request.headers.cookie будет содержать несколько членов.Вам необходимо изучить атрибут value каждого объекта в этом массиве, проверить наличие нескольких значений в каждом из них, а также учесть тот факт, что массив будет полностью неопределенным (не пустым), если файлов cookie не существует.


Бонус: вот функция, которую я написал, которая, я считаю, правильно обрабатывает все случаи, включая случай, когда нет файлов cookie.Он извлечет печенье с именем, которое вы ищете. В именах файлов cookie учитывается регистр .

// extract a cookie value from request headers, by cookie name
// const my_cookie_value = extract_cookie(event.Records[0].cf.request.headers,'MYCOOKIENAME');
// returns null if the cookie can't be found
// https://stackoverflow.com/a/55436033/1695906

function extract_cookie(headers, cname) {

    const cookies = headers['cookie'];
    if(!cookies)
    {
        console.log("extract_cookie(): no 'Cookie:' headers in request");
        return null;
    }

    // iterate through each Cookie header in the request, last to first

    for (var n = cookies.length; n--;)
    {
        // examine all values within each header value, last to first

        const cval = cookies[n].value.split(/;\ /);
        const vlen = cval.length;

        for (var m = vlen; m--;)
        {
            const cookie_kv = cval[m].split('=');
            if(cookie_kv[0] === cname)
            {
                return cookie_kv[1];
            }            
        } // for m (each value)    
    } // for n (each header)

    // we have no match if we reach this point
    console.log('extract_cookie(): cookies were found, but the specified cookie is absent');
    return null;

}
1 голос
/ 12 марта 2019

Можете ли вы добавить еще один каталог: с первым запросом установщика печенья вернуть (из лямбды) перенаправление, содержащее заголовок набора печенья, который перенаправляет на ваш фактический контент?

ОК, долгонаоборот, но:

  • Возьмите инструкцию cookie из входящего запроса
  • Установите это где-нибудь (кеш и т. д.)
  • Пусть запрос получит ваш объект
  • в ответе, также вызовите функцию, которая читает (кэш) и устанавливает заголовок set-cookie в ответе, если необходимо?
...