Почему Axios не отправляет Cookie на бек сайт?
Мой React js SPA на http://localhost:3000 бек на http://api.f-mania (rest api php). В React js использую axios credentials вставил true:
axios.interceptors.request.use((config) => < config.withCredentials = true; return config; >);
в бек вставил:
// Headers header('Access-Control-Allow-Origin: http://localhost:3000'); header('Access-Control-Allow-Credentials: true'); header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE'); header('Access-Control-Allow-Headers: *'); header('Content-Type: application/json');
Выполняю GET запрос в бек но Куки не отправляется хотя в SPA есть cookie.
Особенности withCredentials
Многие знакомы с таким флагом XmlHttpRequest как withCredentials, знают для чего он нужен, какие заголовки нужно использовать с ним в паре, чтобы браузер нормально обрабатывал ответы сервера. И я вроде тоже знал, а что не знал — нагугливал, и всё работало как надо. Но однажды столкнулся с неожиданным поведением, о чём и хочу поведать.
Как указано в спецификации www.w3.org/TR/cors/#omit-credentials-flag, withCredentials позволяет нам использовать в запросе к серверу user-credentials, т.е. куки, аутентификационные данные и клиентские SSL-сертификаты.
Я делаю запрос для получения куки:
$.ajax (< type: 'POST', url: authUrl, dataType: 'json' >);
Сервер возвращает корректный ответ с:
Set-Cookie:MYCOOKIE=7B6E846F8972DF580001CDCBF49316E; Path=/; HttpOnly
Далее я обращаюсь по тому же адресу с полученной кукой:
$.ajax ( < type: 'GET', url: authUrl, dataType: 'json', cache: false, xhrFields: < withCredentials: true >>);
Здесь и происходит неожиданное для меня: хоть я и указал «withCredentials: true», полученная из первого запроса кука не отправляется во втором запросе.
Выясняется, что кука из первого запроса не сохраняется браузером, и отправлять со вторым запросом нечего.
Предположил, что причина в HttpOnly, но проверить с кукой без этого флага не получилось, потому что перед этим попробовал добавить «withCredentials: true» в первый запрос, и происходит чудо — кука сохраняется браузером, и во втором запросе она успешно отправляется.
Таким образом, получается, что указание «withCredentials: true» необходимо не только для отправки «user-credentials» в запросе к серверу, но и для использования их из ответов от сервера. Вроде бы логично, но использование слова «request» во всех спецификациях и описаниях сбивает с толку, надеюсь не только меня)
PS. Как то я упустил эту спецификацию, где прямо написано, что при отсутствии этого атрибута «cookies are to be ignored in response», двойка мне за навыки поиска. Но надеюсь, теперь многие смогут избежать возможного недопонимания.
Withcredentials axios что это
# Axios и Redux-Thunk, асинхронные запросы к бэкенду ## fetch Привычный способ обращения к серверу — функция fetch: «`js const response = await fetch(url, options); const json = await response.json(); «` ## Axios возвращает Promise Как и fetch, axios возвращает Promise. Синтаксис немного отличается: «`js const response = await fetch(url, options); const json = await response.json(); «` ## В чём разница? — корректная поддержка cookie-заголовков — более гибкие настройки — более выразительный интерфейс ## Установка npm: «`sh npm install axios «` yarn: «`sh yarn add axios «` ## Общие запросы «`js // Send a POST request axios( < method: 'post', url: '/user/12345', data: < firstName: 'Fred', lastName: 'Flintstone' >>); // Send a GET request (default method) axios(‘/user/12345’); «` ## Запросы по методам — axios.request(config) — axios.get(url[, config]) — axios.delete(url[, config]) — axios.head(url[, config]) — axios.options(url[, config]) — axios.post(url[, data[, config]]) — axios.put(url[, data[, config]]) — axios.patch(url[, data[, config]]) ## Настройки «`js < url: '/user', method: 'get', // default // базовый адрес, к нему добавляется свойство url для формирования полного адреса baseURL: 'https://some-domain.com/api/', // преобразование всех запросов перед отправкой transformRequest: [function (data, headers) < return data; >], // преобразование ответа transformResponse: [function (data) < // Do whatever you want to transform the data return data; >], // дополнительные заголовки headers: <'X-Requested-With': 'XMLHttpRequest'>, // параметры в адресной строке, GET-параметры params: < ID: 12345 >, // данные для не GET-запросов (POST, PUT и тд), сюда передаётся тело запроса data: < firstName: 'Fred' >, // передача данных в виде строки data: ‘Country=Brasil&City=Belo Horizonte’, // таймаут соединения timeout: 1000, // default is `0` (no timeout) // передача cookie-файлов withCredentials: false, // default // 401-авторизация auth: < username: 'janedoe', password: 's00pers3cret' >, // обработка полученных данных перед отдачей результата // options are: ‘arraybuffer’, ‘document’, ‘json’, ‘text’, ‘stream’, ‘blob’ responseType: ‘json’, // default // ограничение размера передаваемого содержимого maxContentLength: 2000, maxBodyLength: 2000, // максимальное число переходов по переадресациям от сервера maxRedirects: 21, // default // инструменты для отмены запроса // an alternative way to cancel Axios requests using AbortController signal: new AbortController().signal, > «` ## Ответ axios возвращает ответ в виде объекта со следующими свойствами «`js axios.get(‘/user/12345’) .then(function (response) < console.log(response.data); console.log(response.status); console.log(response.statusText); console.log(response.headers); console.log(response.config); >); «` ## Отмена запроса «`js const controller = new AbortController(); axios.get(‘/foo/bar’, < signal: controller.signal >).then(function(response) < //. >); // cancel the request controller.abort() «` ## Настройки в рамках клиента Для разделения настроек при работе с несколькими API, можно создать свой экземпляр axios через axios.create «`js const instance = axios.create(); instance.defaults.timeout = 2500; instance.get(‘/longRequest’, < timeout: 5000 >); «` ## Шаблон Посредник Представляет цепочку функций: — каждая обрабатывает свою часть запроса — если в процессе проверки возникают ошибки, следующие в цепочке функции не запустятся «`js const user = < name: 'Oleg', age: 18, active: true >; const checkAge = (data, next) => < if (data.age >= 18) < return next(); >console.log(‘Вы слишком молоды!’); > const checkLastName = (data, next) => < if (data.lastName) < return next(); >console.log(‘У вас нет фамилии!’); > const checkActive = (data, next) => < if (data.active) < return next(); >console.log(‘Будьте активнее!’); >; const action = (data) => < console.log('вы справились!'); >const middlewares = [checkAge, checkLastName, checkActive, action]; const run = (payload, chain) => < const done = () =>true; for (const fn of chain) < if (fn(payload, done) !== true) < return; >> > run(user, middlewares); «` ## Redux Thunk По факту входит в состав redux toolkit и позволяет запускать дочерние и отложенные действия «`js export const incrementIfOdd = (amount) => (dispatch, getState) => < const currentValue = selectCount(getState()); if (currentValue % 2 === 1) < dispatch(incrementByAmount(amount)); >>; «` ## Преимущества — Запуск действий из действий (цепочка действий) — Даёт доступ к dispatch — Поддержка Promise в действиях'X-Requested-With':>
Last changed by
Read more
Техническое задание
Сделать дизайн статьи. Цель Макет будут использовать в бесплатном курсе по вёрстке. Поэтому желательно продемонстрировать максимум техник вёрстки текста. При этом дизайн должен смотреться гармонично и минималистично Требования к дизайну Дизайн должен включать:
Как общаться с душнилами
«Лучший способ справиться с душнилой — быть таким интересным, чтобы они перестали говорить только о себе.» — Джон Бернхард Шоу Иногда мы сталкиваемся с людьми, которые могут быть скучными, неприятными или надоедливыми. Их называют «душнилами». В этой статье мы поделимся простыми советами, которые помогут вам общаться с такими людьми. Оглавление Виды душнил Как опознать душнилу Виды душнил Что делать Если ничего не помогло
Медитация покоя
Цель: достижение внутреннего покоя и гармонии. «Медитация — это искусство тишины в движении.» — Кришнамурти «Медитация — это способ вернуться к центру своего существа.» — Ошо «Медитация — это ключ к открытию потока внутреннего покоя.» — Джек Корнфилд Оглавление Введение
Redux, менеджмент состояний
Зачем нужен Redux Toolkit? Упрощает подключение redux к React Снижает количество дублированного кода Обзор redux, react-redux, redux toolkit — что и зачем redux — библиотека для управления состоянием приложения react-redux — библиотека для подключения redux к react redux-toolkit — набор инструментов для сокращения дублей кода и упрощения файловой структуры проекта Отличия и основы пакетов
Axios
Axios — популярная клиент-серверная библиотека для выполнения HTTP-запросов .
Возможности
Axios предоставляет следующие возможности:
- отправка XMLHttpRequest из браузера
- отправка HTTP-запросов из Node.js
- поддержка Promise API
- перехват запросов и ответов
- преобразование данных запросов и ответов
- отмена/прерывание запроса
- автоматический разбор/парсинг данных в формате JSON
- автоматическая защита от XSRF
Установка
yarn add axios # или npm i axios
Примеры отправки GET и POST-запросов
// GET-запрос const getUserById = async (userId) => try const response = await axios.get(`/users?id=$userId>`) return response.data > catch (err) console.error(err.toJSON()) > > getUserById('1') // POST-запрос const addNewUser = async (newUser) => try const response = await axios.post('/users', newUser) return response.data > catch (err) console.error(err.toJSON()) > > addNewUser( firstName: 'John', lastName: 'Smith' >)
Пример отправки нескольких запросов
// Первый запрос const getUserAccount = () => axios.get(`/user/123`) // Второй запрос const getUserPermissions = () => axios.get('/user/123/permissions') // Отправка обоих запросов const getUserInfo = async () => const [account, permissions] = await Promise.all([getUserAccount(), getUserPermissions()]) return account, permissions > >
Настройки запроса
url: '/users', method: 'get', // default baseURL: 'http://example.com', // Преобразование запроса transfromRequest: [(data, headers) => return data >], // Преобразование ответа transformResponse: [(data) => return data >], headers: 'Authorization': 'Bearer [token]' >, data: firstName: 'John' >, // Параметры строки запроса params: id: '123' >, withCredentials: false, // default responseType: 'json', // default responseEncoding: 'utf8', // default // Прогресс загрузки файлов onUploadProgress: (e) => >, // Прогресс скачивания файлов onDownloadProgress: (e) => >, // Максимальный размер ответа в байтах maxContentLength: 2048, // Максимальный размер запроса в байтах maxBodyLength: 2048, proxy: protocol: 'https', host: '127.0.0.1', port: 5000, auth: username: 'John', password: 'secret' > >, // Токен для отмены запроса cancelToken: new CancelToken((cancel) => >) >
Схема ответа
data: >, status: 200, statusText: 'OK', headers: >, config: >, request: > >
Настройки по умолчанию
axios.defaults.baseURL = 'http://example.com' // Дефолтные настройки общих заголовков axios.defaults.headers.common['Authorization'] = TOKEN // Дефолтные настройки для POST-запроса axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded'
Перехватчики
Мы можем перехватывать запросы или ответы перед их обработкой в then или catch .
// Перехватчик запроса axios.interceptors.request.use((config) => return config >, (error) => return Promise.reject(error) >) // Перехватчик ответа axios.interceptors.response.use((response) => return response >, (error) => return Promise.reject(error) >)
Обработка ошибок
const getUserById = (userId) => try const data > = await axios.get(`/users?id=$userId>`) return data > catch (error) if (error.response) // Статус ответа выходит за пределы 2xx const data, status, headers > = error.response console.error(data) > else if (error.request) // Отсутствует тело ответа console.error(error.request) > else // Ошибка, связанная с неправильной настройкой запроса console.error(error.message) > // Другая ошибка console.error(error.config) // Подробная информация об ошибке console.error(error.toJSON()) > >
Отмена запроса
const CancelToken > = axios const source = CancelToken.source() const getUserById = (userId) => try const data > = await axios.get(`/users?id=$userId>`) return data > catch (thrown) if (axios.isCancel(thrown)) console.error(thrown.message) > else // Обработка ошибки > > > // Отмена запроса (параметр `message` является опциональным) source.cancel('Выполнение операции отменено')