Практика использования файлов cookie для торговых апплетов JD.com

Апплет WeChat

Автор: Чжан Чжихао

Введение

В первые дни, чтобы удовлетворить потребность в «сохранении сеанса», в сообществе появилось «решение для файлов cookie», которое в конечном итоге стало стандартом W3C: когда веб-сайт успешно входит в систему, клиент (браузер) получает идентификатор файла cookie. (текст) и сохраняет его.Это поле будет автоматически включено в последующие запросы, чтобы веб-фон мог определить, является ли это тот же пользователь, чтобы «сеанс» мог продолжаться.

Апплет WeChat не имеет встроенного решения для файлов cookie, такого как браузер, и разработчикам необходимо имитировать его самостоятельно.Исходный апплет для покупок Jingdong и апплет Jingxi (теперь портал для покупок первого уровня WeChat) перенесены и итерированы из WeChat и мобильные QQ покупки H5, То есть мы должны не только смоделировать набор решений для файлов cookie в апплете, но и сохранить ту же логику обработки файлов cookie, что и исходный бизнес. По этой причине мы устанавливаем направление реализации как «на основе открытость апплета и согласованность».

Апплет WeChat открытКэш данных Хранилищеа такжесетьЭти две возможности, с помощью этих двух наборов API, позволяют нам самостоятельно создать решение для файлов cookie.

PS: Весь код и примеры использования в этой статье можноэто здесьНайдите и прочитайте эту статью с практикой, эффект лучше.

2. Файлы cookie в браузере

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

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

  • Локальное хранилище: браузер выделит место локально для хранения файлов cookie.
  • Перенос запроса: каждый раз, когда делается запрос, файл cookie будет извлекаться локально и добавляться к заголовку запроса.
  • Параметры ответа: если в заголовке ответа есть поле Set-Cookie, его необходимо проанализировать и обновить.
  • Время истечения срока действия: каждое поле cookie имеет отдельное время истечения срока действия, и срок действия будет автоматически очищен.
  • Чтение и запись: разоблачение API, чтобы позвонить в интерфейс JS, чтобы увеличить модификацию
  • Область действия: путь path, доменное имя домена
  • Кодировка: значение cookie, для передачи по сети требуется кодировка, рекомендуется хранить то же самое
  • Другие: HttpOnly, Secure, SameSite

в браузереDevTools, вы можете увидеть информацию о файлах cookie под текущим сайтом:

Chrome Cookie面板截图

3. Реализация куки в апплете

Дизайн

Имитация файлов cookie в мини-программах в основном состоит из пяти частей:

小程序cookie方案设计图
Среди них мы остановимся на реализации «Базовой библиотеки файлов cookie», а также приведем пример упаковки «Базовой библиотеки запросов».

локальное хранилище

Апплет предоставляет «API хранилища кэша данных» (который можно понимать какLocalStorage), который поддерживает хранение «примитивных типов, дат и объектов, которые можно сериализовать с помощью JSON.stringify».

Мы можем использовать эти API, чтобы открыть новый в хранилище.cookiesполе для хранения:

// 存:
wx.setStorageSync('cookies', cookies)
// 取:
wx.getStorageSync('cookies')

вcookies«Структура хранения» выглядит следующим образом:

// cookies = 
{
    cookie1: { // “最小cookie单元” ==> cookieItem
        name: 'cookie1', // cookie名
        value: 'xxx',    // cookie值
        expires: 'Fri, 17 Jan 2020 08:49:41 GMT' // 过期时间,使用GMT(格林威治标准时间)格式
    }
},

надcookie1это "минимальная единица cookie"cookieItem", содержит 3 поля (имя, значение, срок действия), является "стандартным форматом файлов cookie", определенным в этой статье, а также является базовой единицей работы с файлами cookie.

Откройте [Инструменты разработки WeChat]Storageна вкладке вы можете просмотреть ситуацию с локальным хранилищем:

Storage面板截图

операции чтения и записи

Эта часть в основном действует как «общедоступная базовая библиотека», предоставляя API для добавления, удаления, изменения и проверки файлов cookie для внешних компаний.

1. Получить куки————getCookie()

Шаг: Извлеките полные файлы cookie из хранилища ==> Извлеките элемент cookie с указанным именем ==> Проверьте срок действия ==> Возвращаемое значение

Реализация выглядит следующим образом:

function getCookie(name = '') {
    let cookies = wx.getStorageSync('cookies') // try/catch 略过
    let { value, expires } = cookies[name] || {}

    return (name && expires && !isExpired(expires)) ? decodeURIComponent(cookieItem.value) : ''
}

2. Установка файлов cookie————setCookie()

Шаг: Возьмите полные файлы cookie из хранилища ==> Проанализируйте входные параметры ==> Перезапишите обновление ==> Синхронизируйте с локальным хранилищем

Сначала взгляните на требования к дизайну этого API:

  • Установить одиночные/множественные файлы cookie
  • Передать значение напрямую/передать cookieItem (объект)
  • Формат времени maxAge/expires

Пример вызова выглядит следующим образом:

setCookie({
    cookie1: 12345,
    cookie2: '12345'
})

setCookie({
    cookie1: {
        value: 12345,
        maxAge: 3600 * 24  // 自定义有效期(这里示例是24小时)
    },
    cookie2: {
        value: '12345',
        expires: 'Wed, 21 Oct 2015 07:28:00 GMT' // 标准GMT格式
    }
})

Здесь входные параметры могут быть пройдены, и подэлемент cookie может быть получен в максимально возможной степени независимо от того, передается ли значение напрямую или передается подробный объект.name/value/expires/maxAgeПередать функцию форматирования на стандартcookieItem:

function setCookie(cookiesParam) {
    let oldCookies = wx.getStorageSync('cookies') // try/catch 略过
    let newCookies = {} // 由 cookiesParam 转化为标准格式后的cookies

    for (let name in cookiesParam) {
        if (isObject(cookiesParam[name])) { // 传入是Object格式
            let { value, expires, maxAge } = cookiesParam[name]
            // 转换为标准cookie格式(cookieItem)
            newCookies[name] = getStandardCookieItem({ name, value, expires, maxAge })
        } else {
            newCookies[name] = getStandardCookieItem({ name, value: cookiesParam[name] })
        }
    }

    // 同步到本地Storage
    saveCookiesToStorage(Object.assign({}, oldCookies, newCookies))
}

3. Удалить файлы cookie————removeCookie()

Шаги: Удалить полные файлы cookie из хранилища ==> Удалить указанный элемент файла cookie ==> Синхронизировать с локальным хранилищем.

function removeCookie(cookieName) {
    let cookies = wx.getStorageSync('cookies') // try/catch 略过

    delete cookies[cookieName]

    saveCookiesToStorage(Object.assign({}, cookies))
}

4. Передача куки в сети

Этот раздел в основном кратко реализует часть [Запрос базовой библиотеки] схемы проекта.

network-transfer

Как показано на рисунке выше, существует четыре основных процесса передачи файлов cookie в сети:

  1. Клиент инициирует HTTP-запрос
  2. Сервер отвечает и добавляет заголовок ответаSet-Cookie, клиент принимает и анализирует сохранение
  3. В следующий раз, когда клиент инициирует HTTP-запрос, добавьте его в заголовок запроса.Cookie
  4. Сервер распознает заголовок запросаCookie, произвести соответствующую обработку

Ниже приведен пример захвата пакета для запроса:

request-demo

В апплете есть два способа инициировать запрос:HTTPа такжеWebSocket, здесь в качестве примера используется HTTP, сначала «инкапсулируйте» API запроса:

function requestPro({ url, data, header, method = 'GET' }) {
    return new Promise((resolve, reject) => {
        wx.request({
            url,
            data,
            header: Object.assign({}, { 'Cookie': CookieLib.getCookiesStr() }, header), // 请求头————带上Cookie
            success (res) {
              let { data : resData, header, statusCode } = res
              let setCookieStr = header['Set-Cookie'] || header['set-cookie'] || ''

              CookieLib.setCookieFromHeader(setCookieStr) // 响应头————解析Set-Cookie
              resolve(resData)
            },
            fail (err) {
                reject(err)
            }
          })
    })
}

Как показано в приведенном выше коде, обработка файлов cookie во внешнем модуле запроса в основном включает три пункта:

1. Запрос на перенос

Шаги: (Перед каждым запросом) Извлеките полные файлы cookie из хранилища ==> Преобразуйте в стандартный заголовок HTTP-запроса Формат файла cookie ==> Установите наRequest Headerсередина

в коде вышеgetCookiesStr()Пример возврата прямого доступа к файлам cookie:cookie1=xxx;cookie2=yyy.

2. Настройки ответа

Шаги: (после каждого полученного ответа) разборResponse HeaderизSet-CookieПоле ==> Преобразовать в стандартный формат Cookie ==> setCookie()

разобраться с этимSet-CookieКогда дело доходит до контента, нужно помнить о нескольких вещах: - Самый простой формат:Set-Cookie: <cookie-name>=<cookie-value>- Может содержать несколько полей cookie одновременно, разделенных , (но необходимо исключить , в значении времени) - Формат времени: Max-Age/Expires (без учета регистра)

Конкретную реализацию можно найти в демо в конце статьи.

3. Проблемы с кодированием

«Метод кодирования значения куки» — это место, которое легко вызвать путаницу, и широко используемая практика заключается в использовании «кодирования URL».

Но я читалRFC6265Обнаружено, что кодировка не указана в исходной спецификации, например, она описана в Главе 4 Требования к серверу (Сервер):

To maximize compatibility with user agents, servers that wish to store arbitrary data in a cookie-value SHOULD encode that data, for example, using Base64 [RFC4648].

«Для лучшей совместимости серверу СЛЕДУЕТ кодировать значение cookie, например, с использованием Base64».

В главе 5 «Требования к пользовательскому агенту» (клиент, то есть браузер) «рекомендуется подчиняться реализации главы 4 сервера».

Короче говоря, спецификация не определяет использование «кодирования URL», но поскольку схема кодирования глубоко укоренилась в сердцах людей, она, естественно, стала «выбором по умолчанию». Тогда здесь нет никаких исключений.Как это делает браузер и апплет тоже непротиворечивы.

В браузере рекомендуемое значение cookie передается черезencodeСохраните его после кодирования, так что то, что вы получите напрямую, такжеencodeпосле значения, поэтому добавьте его в заголовок запросаCookieполе, вам не нужноdecodeПосле декодирования его можно сплайсировать напрямую (но в конечном итоге нужно выполнить операцию получения API базовой библиотекиdecodeрасшифровка).

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

Пять, оптимизация производительности (высокочастотное чтение и запись)

В предыдущей реализации каждый раз при чтении и записи файла cookie будет вызываться API хранилища апплета (и это синхронно), а структура апплета будет читать и записывать в локальное хранилище. Для высокочастотных сценариев вы можете хранить копию файла cookie в памяти, читать и записывать непосредственно через «уровень памяти» и синхронизироваться со «уровнем хранения» при обновлении.

1. Инициализировать

Сначала нужно объявить_COOKIES(названный DIY), рекомендуется объявить его в базовой библиотеке файлов cookie для унифицированного обслуживания.

2. Читать

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

3. Пишите

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

6. Модульное тестирование

WeChat официально запустил «Mini Program Automation SDK» в мае 2019 года.miniprogram-automator, После более чем полугодовой итерации он в основном стабилизировался.

Я попробовал его на сцене апплета для покупок, и вариант использования, связанный с файлами cookie, был завершен быстро, что просто благословение для разработчиков: действительно ароматный! ! !

smells-good

В реальных проектах модульные тесты для файлов cookie можно разделить на две категории:

  1. Проверка файлов cookie в глобальной области действия апплета (например, после инициализации апплета устанавливаются ли какие-либо ключевые файлы cookie, такие как номер версии и поведение при доступе)
  2. Проверка API базовой библиотеки файлов cookie (например, получение/установка/удаление и другие API работают правильно)

ПроверятьsetCookie()Пример API:

it('API验证:setCookie()', async () => {
    await miniProgram.evaluate(() => {
        wx.CookieLib.setCookie({ // 调用API
            cookie1: 12345,
        })
    })

    let { cookies } = await miniProgram.callWxMethod('getStorageSync', 'cookies')
    expect(cookies['cookie1'].value).toBe(12345) // 期望成功设置cookie1为12345
})

Здесь, чтобы облегчить тестовый пример для вызова API базовой библиотеки, перед запуском апплета базовая библиотека Cookie (CookieLib) связана сwxНа объекте метод реализации заключается в использовании API узла для чтения и записи файлов в [код импланта]:

fs.appendFileSync('./your_project/app.js', ''\n wx.CookieUtil = require(\'./lib/cookie.js\');\n'')

7. Безопасность файлов cookie

Безопасность файлов cookie — это относительно большая тема, вот лишь несколько моментов, связанных с мини-программами.

путь, домин, HttpOnly, Secure, SameSite

В апплете предприняты некоторые меры безопасности, например, использование только HTTPS, администратору необходимо настроить легитимное доменное имя в фоновом режиме WeChat, доступ к хранилищу может получить только апплет, который его записывает, и так далее. следовательноpath、domin、HttpOnly、Secure、SameSiteЗначение этих полей в среде апплета не такое большое, как в среде браузера, в данном примере оно не используется (ленивый..), но реальный бизнес-сценарий может решить, использовать ли его в соответствии со своей ситуацией .

Механизм белого списка

  1. Техническое обслуживание внешнего интерфейса (размер/количество) Обычно данные cookie, хранящиеся в браузере, не превышают 4 КБ, а некоторые браузеры ограничивают максимальное количество файлов cookie на одном сайте до 20. Если бизнес огромен, рекомендуется создать механизм «белого списка» в базовой библиотеке файлов cookie, и запись может выполняться только в белом списке, чтобы предотвратить проблемы «незаконного написания» или «потеря информации из-за слишком большое содержание».

  2. Фоновое обслуживание (Hateway Whitelist) Точно так же рекомендуется установить «доверенный файл cookie» из уровня шлюза, чтобы автоматически фильтровать поле «незаконное файло cookie» в запросе.

Передняя часть с защитой от несанкционированного доступа

Внешний интерфейс апплета больше предназначен для предотвращения «ошибочной модификации», то есть в процессе работы с файлами cookie произошли неожиданные модификации. Обычно происходит в функциях «эталонной копии» JS, таких как вышеупомянутое обслуживание памяти._Cookies, если есть APIgetAllCookies()Путем непосредственного предоставления этой версии файлов cookie в памяти ссылка на объект легко модифицируется. Следовательно, базовой библиотеке файлов cookie необходимо контролировать возможности предоставления доступа к API и делать «глубокую копию» значения.

Session

Механизм сеанса поддерживает состояние пользователя на стороне сервера, который имеет лучшую безопасность.В настоящее время различные серверные части имеют зрелые технические решения для хранения и синхронизации сеансов.Условные предприятия должны использовать сеанс в качестве основного сеанса.Сохранить.

Отчет об отпечатках пальцев

Отпечаток устройства генерируется и сообщается (обычно в процессе входа в систему/расчета), когда пользователь получает доступ, а бизнес-фон взаимодействует с системой управления рисками, чтобы инициировать процесс проверки при обнаружении ненормального запроса.

Восемь, завершите апплет, чтобы получить демонстрацию

сегмент кода:Developers.WeChat.QQ.com/Yes/Small 4sf ASM будет 7…

Demo工程截图

9. Резюме

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

10. Ссылки по теме


Если вы считаете, что этот контент ценен для вас, пожалуйста, поставьте лайк и подпишитесь на нашуОфициальный сайтИ наш публичный номер микроканала (WecTeam), каждую неделю публикуем качественные статьи:

WecTeam