Teamescript Refactoring Axios Опыт обмена опытом

HTTP TypeScript Promise axios

Откажитесь быть инженером документации только по API, эта статья позволит вам освоить основы веб-разработки, особенно XMLHttpRequest, из процесса изобретения колеса.

Еще один обмен информацией о TypeScript в конце года, пожалуйста, позвольте мне договориться. Последний рефакторинг Vconsole с помощью TypeScriptпроектпохоронен прямоAxiosСтебель анализа исходного кода. Поэтому тема этого обменаКак провести рефакторинг Axios с нуля с помощью TypeScript и зачем я это делаю.

Цель автора при воссоздании колеса с помощью TypeScript до сих пор очень ясна.Не только для того, чтобы выработать хорошую привычку разработки с помощью TypeScript, но, что более важно, для понимания основ ассоциации библиотек инструментов.Только сосредоточившись больше на основах, можно как можно быстрее избавиться от хлопот инженера-документатора. (Ps: использование TypeScript также позволяет избавиться от участи проверки документов на внешнем интерфейсе!)

Это совместное использование включает в себя следующее:

  • Инженерное введение и советы по развитию
  • Реализация API
  • XHR, XHR, XHR
  • HTTP, HTTP, HTTP
  • модульный тест

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

грамм

Что такое Аксиос?

Promise based HTTP client for the browser and node.js

axios — это HTTP-клиент на основе Promise для браузеров и nodejs.Он имеет следующие функции (√ означает, что этот проект имеет эту функцию):

  • √ Создать XMLHttpRequest из браузера =>XHR Реализация
  • √ Поддержка Promise API =>Реализация XHR
  • √ Перехватывать запросы и ответы =>запрос на перехват
  • √ Преобразование данных запроса и ответа => соответствующий каталог проекта/src/core/dispatchRequest.ts
  • √ Отменить запросотменить запрос
  • √ Автоматически преобразовывать данные JSON => соответствующий каталог проекта/src/core/dispatchRequest.ts
  • √ Поддержка клиентов для предотвращения CSRF/XSRF =>CSRF
  • × Делайте http-запросы из node.js

Здесь мы в основном объясним реализацию XHR на стороне браузера и не будем использовать http под узлом из-за нехватки места. Если вы хотите понять это слой за слоем, вы обнаружите, что реализация аксиом по-прежнему очень проста, давайте исследовать вместе!

Каталог Описание

Сначала загляните в каталог.

Каталог в основном такой же, как и у Axios, а ядроAxiosОсновной код класса. adapters — это основная реализация XHR, а Cancel — код, связанный с отменой запроса. хелперы используются для размещения часто используемых служебных функций.Karma.conf.jsи тестовый каталог, связанный с модульными тестами..travis.ymlдля конфигурацииНепрерывная онлайн-интеграция, и вы можете настроить ситуацию сборки в файле README на github.

Интеграция посылок

Выбранный инструмент упаковкиParcel, целью которого является компиляция TypeScript с нулевой конфигурацией. Файл записи находится в каталоге srcindex.html, просто импортируйте его в файл вводаindex.tsКонфигурации, такие как горячее обновление и компиляция TypeScript, могут быть выполнены:

<body>
  <script src="index.ts"></script>
</body>

Относящиеся к посылке:

# 全局安装
yarn global add parcel-bundler

# 启动服务
parcel ./src/index.html

# 打包
parcel build ./src/index.ts

отладка VScode

Запуск команды посылки запустит локальный сервер, доступ к которому можно получить через.vscodeв каталогеlaunch.jsonНастройте инструмент отладки Vscode.

{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "chrome",
      "request": "launch",
      "name": "Lanzar Chrome contra localhost",
      "url": "http://localhost:1234",
      "webRoot": "${workspaceRoot}",
      "sourceMaps": true,
      "breakOnLoad": true,
      "sourceMapPathOverrides": {
        "../*": "${webRoot}/*"
      }
    }
  ]
}

После настройки вы можете отладить точку останова, нажмите F5, чтобы начать отладку.

Конфигурация TypeScript

Общий справочник по обнаружению конфигурации и спецификаций TypeScript выглядит следующим образом:

Настоятельно рекомендуется включитьtslint, установить vscodeплагин tslintИ в.vscodeв каталоге.settingКонфигурация имеет следующий формат:

{
  "editor.tabSize": 2,
  "editor.rulers": [120],
  "files.trimTrailingWhitespace": true,
  "files.insertFinalNewline": true,
  "files.exclude": {
    "**/.git": true,
    "**/.DS_Store": true
  },
  "eslint.enable": false,
  "tslint.autoFixOnSave": true,
  "typescript.format.enable": true,
  "typescript.tsdk": "node_modules/typescript/lib"
}

если установленPrettierСледует отметить, что стили двух конфликтуют, независимо от того, какой плагин для форматирования кода, наша цель только одна, которая заключается в обеспечении единообразия стиля форматирования кода. (Лучше всего следовать спецификации ворса).

пс:.vscodeКаталоги можно отслеживать в управлении версиями с помощью git, что делает репозитории клонов более удобными для пользователя.

Кроме того, его можно передать, vscode'sВкладка «Проблемы» в панели управленияБыстро увидеть, что не так с вашим текущим проектом.

Тестирование фрагмента кода TypeScript

У нас часто возникает необходимость отредактировать определенный тестовый код, но не хочется писать его в проекте (например, писать функцию deepCopy на TypeScript).Если вы не хотите выходить из редактора vscode, рекомендуется использоватьquokka, плагин, который мгновенно выполняет скрипты.

  • Если вам нужно импортировать другую ссылку на библиотекуконфигурация квокки
  • Если вы хотите представить среду браузера, вы можете установить ее глобально в каталоге проекта quokkajs.jsdom-quokka-pluginплагин

тогда вот так

({
  plugins: 'jsdom-quokka-plugin',
  jsdom: { html: `<div id="test">Hello</div>` }
});

const testDiv = document.getElementById('test');

console.log(testDiv.innerHTML);

Обзор API

Идея рефакторинга заключается в том, чтобы сначала посмотреть на API, предоставленный документацией, илиindex.d.tsфайл декларации. Для лучшего исходного кода вы можете посмотреть его тестовые случаи, и обычно предоставляют тесты, связанные с API, такие какТестовый пример AXIOS API, этот API реализации совместного использования выглядит следующим образом:

Всего существует пять типов API, которых меньше, чем тыквенный ребенок. Наберитесь терпения, давайте "отправлять головы" по одной.

Аксиос класс

Эти API можно в совокупности назвать методами экземпляра, и если есть экземпляр, должен быть и класс. Итак, прежде чем говорить о реализации API, давайте взглянем на класс Axios.

Два свойства (дефолты, перехватчики), общий метод (запрос, остальные методы типа get, post и т.д. основаны на запросе, но параметры разные) действительно проще не бывает.

export default class Axios {
  defaults: AxiosRequestConfig;
  interceptors: {
    request: InterceptorManager;
    response: InterceptorManager;
  };
  request(config: AxiosRequestConfig = {}) {
    // 请求相关
  }
  // 由 request 延伸出 get 、post 等
}

экземпляр axios

По умолчанию библиотека Axios является Axios Axios Axios вместо самого класса Axios. Однако это не напрямую возвращается в пример Axio, но установить контекст запроса метода экземпляра Axios в Axios. Таким образом, тип Axios является функцией, а не объектом. Однако из-за функции можно установить объект, атрибуты и методы. Таким образом, Axios может вести себя в качестве примера, но и напрямую функционируют вызовaxios(config). Конкретная реализация выглядит следующим образом:

const createInstance = (defaultConfig: AxiosRequestConfig) => {
  const context = new Axios(defaultConfig);
  const instance = Axios.prototype.request.bind(context);
  extend(instance, Axios.prototype, context);
  extend(instance, context);
  return instance;
};

axios.create = (instanceConfig: AxiosRequestConfig) => {
  return createInstance(mergeConfig(axios.defaults, instanceConfig));
};

const axios: AxiosExport = createInstance(defaults);

axios.Axios = Axios;

export default axios;

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

Конфигурация Axios по умолчанию

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

Давайте посмотрим на конфигурацию по умолчанию:

const defaults: AxiosRequestConfig = {
  headers: headers(), // 请求头
  adapter: getDefaultAdapter(), // XMLHttpRequest 发送请求的具体实现
  transformRequest: transformRequest(), // 自定义处理请求相关数据,默认有提供一个修改根据请求的 data 修改 content-type 的方法。
  transformResponse: transformResponse(), // 自定义处理响应相关数据,默认提供了一个将 respone 数据转换为 JSON格式的方法
  timeout: 0,
  xsrfCookieName: 'XSRF-TOKEN',
  xsrfHeaderName: 'X-XSRF-TOKEN',
  validateStatus(status: number) {
    return status >= 200 && status < 300;
  }
};

Тем не менее, если вы используете Axios, вы должны знать, какие у него настройки по умолчанию.

Входящая конфигурация Axios

Во-первых, давайте посмотрим на атрибуты параметров запроса, принимаемые axios.Следующие атрибуты параметров являются необязательными. Используйте TypeScript, чтобы заранее определить типы этих параметров, а затем вы можете проверить правильность типов параметров при передаче параметров.

export interface AxiosRequestConfig {
  url?: string; // 请求链接
  method?: string; // 请求方法
  baseURL?: string; // 请求的基础链接
  xsrfCookieName?: string; // CSRF 相关
  xsrfHeaderName?: string; // CSRF 相关
  headers?: any; // 请求头设置
  params?: any; // 请求参数
  data?: any; // 请求体
  timeout?: number; // 超时设置
  withCredentials?: boolean; // CSRF 相关
  responseType?: XMLHttpRequestResponseType; // 响应类型
  paramsSerializer?: (params: any) => string; // url query 参数格式化方法
  onUploadProgress?: (progressEvent: any) => void; // 上传处理函数
  onDownloadProgress?: (progressEvent: any) => void; // 下载处理函数
  validateStatus?: (status: number) => boolean;
  adapter?: AxiosAdapter;
  auth?: any;
  transformRequest?: AxiosTransformer | AxiosTransformer[];
  transformResponse?: AxiosTransformer | AxiosTransformer[];
  cancelToken?: CancelToken;
}

запросить конфигурацию

  • url
  • method
  • baseURL
export interface AxiosRequestConfig {
  url?: string; // 请求链接
  method?: string; // 请求方法
  baseURL?: string; // 请求的基础链接
}

Сначала рассмотрим соответствующие знания:

URL, метод какXMLHttpRequestсерединаopenПараметры метода.

Открытый синтаксис:xhrReq.open(method, url, async, user, password);

URL-адресDOMString, который представляет URL-адрес, с которого был отправлен запрос.

Примечание. Передача null | undefined методу или параметру, который принимает DOMString, обычно преобразует его в строку «null» | «undefined».

Используйте собственный метод открытия для передачи следующих параметров, и фактический URL-адрес запроса выглядит следующим образом:

let xhr = new XMLHttpRequest();

// 假设当前 window.location.host 为 http://localhost:1234

xhr.open('get', ''); // http://localhost:1234/
xhr.open('get', '/'); // href http://localhost:1234/
xhr.open('get', null); // http://localhost:1234/null
xhr.open('get', undefined); // http://localhost:1234/undefined

Вы можете видеть, что базовый URL-адрес по умолчаниюwindow.location.hostаналогичныйhttp://localhost:1234/undefinedБывают случаи, когда запрос URL-адреса выполняется успешно. Когда внешний интерфейс динамически передает параметры URL, параметры могут бытьnullилиundefined, если вы не отвечаете на операцию через статус-код ответа, результат, полученный в это время, отличается от того, что вы ожидали.Это напоминает мне о ловушках неявных преобразований JavaScript повсюду. (Здесь Amway TypeScript и оператор '===')

В таких случаях использование TypeScript может обойти эти проблемы во время разработки. Но если это динамическое присвоение (например, когда результат, возвращаемый запросом, используется в качестве параметра URL), вам нужно судить о типе значения, и при необходимости вы можете выдать ошибку или преобразовать его в другой желаемый значения.

Далее, давайте взглянем на URL-адрес, связанный с axios, который в основном обеспечивает поддержку baseURL, доступ к которому можно получить черезaxios.defaults.baseURLилиaxios({baseURL:'...'})

const isAbsoluteURL = (url: string): boolean => {
  // 1、判断是否为协议形式比如 http://
  return /^([a-z][a-z\d\+\-\.]*:)?\/\//i.test(url);
};
const combineURLs = (baseURL: string, relativeURL: string): string => {
  return relativeURL
    ? baseURL.replace(/\/+$/, '') + '/' + relativeURL.replace(/^\/+/, '')
    : baseURL;
};
const suportBaseURL = () => {
  // 2、baseURL 处理
  return baseURL && !isAbsoluteURL(url) ? combineURLs(baseURL, url) : url;
};

параметры и данные

Разница между параметрами и данными при отправке запроса в axios:

  • params добавляется в строку запроса URL-адреса для запросов на получение.

  • данные добавляются в тело запроса для почтовых запросов.

params

Обработка параметров с помощью axios делится на присваивание и сериализацию (пользователи могут настраивать функцию paramsSerializer).

в каталоге помощниковbuildURLФайл в основном генерирует полный URL-адрес запроса.

data

XMLHttpRequest передается черезsendметод для добавления данных в тело запроса.

Синтаксис следующий:

send();
send(ArrayBuffer data);
send(ArrayBufferView data);
send(Blob data);
send(Document data);
send(DOMString? data);
send(FormData data);

Вы можете видеть, что данные имеют следующие типы:

  • ArrayBuffer
  • ArrayBufferView
  • Blob
  • Document
  • DOMString
  • FormData

Я хочу знать, какие типы данных доступны для просмотраэто

фактическое использование:

var xhr = new XMLHttpRequest();
xhr.open('GET', '/server', true);

xhr.onload = function() {
  // 请求结束后,在此处写处理代码
};

xhr.send(null);
// xhr.send('string');
// xhr.send(new Blob());
// xhr.send(new Int8Array());
// xhr.send({ form: 'data' });
// xhr.send(document);

Кроме того, заголовок Content-Type должен быть установлен в соответствии с типом данных с помощью метода setRequestHeader() для указания MIME-типа потока данных перед отправкой запроса, т.е. вызовом метода send().

Аксиос вtransformRequestВ элементе конфигурации есть метод по умолчанию для изменения запроса (настраиваемый).

const transformRequest = () => {
  return [
    (data: any, headers: any) => {
      // ...根据 data 类型修改对应 headers
    }
  ];
};

HTTP связанные

Метод HTTP-запроса

axios предоставляет методы для настройки HTTP-запросов:

export interface AxiosRequestConfig {
  method?: string;
}

Необязательная конфигурация выглядит следующим образом:

  • GET: запросить представление указанного ресурса. Запросы с использованием GET следует использовать только для получения данных.
  • HEAD: метод HEAD запрашивает ответ, идентичный запросу GET, но без тела.
  • POST: используется для отправки объекта (данных) указанному ресурсу, что обычно приводит к изменению состояния или побочному эффекту на сервере.
  • PUT: заменить все текущие представления целевого ресурса полезной нагрузкой запроса.
  • УДАЛИТЬ: удалить указанный ресурс.
  • ВАРИАНТЫ: параметры связи, используемые для описания целевого ресурса.
  • PATCH: изменить часть приложения ресурса.

Тогда узнайHTTP-запрос

HTTP определяет набор методов запроса, чтобы указать действие, которое должно быть выполнено на данном ресурсе. Указывает на желаемое действие, которое необходимо выполнить с данным ресурсом. Хотя они также могут быть существительными, эти методы запроса иногда называют HTTP-глаголами. Каждый метод запроса реализует различную семантику, но некоторые общие характеристики являются общими для группы: Например, запрос метод может быть безопасным, идемпотентным или кэшируемым.

  • безопасный: говоря, что метод HTTP является безопасным, означает, что это метод, который не изменяет данные сервера. То есть это метод для операций только для чтения на сервере. Эти методы безопасны: GET, HEAD и OPTIONS. Некоторые небезопасные методы, такие как PUT и DELETE, не являются таковыми.

  • идемпотентный: метод HTTP является идемпотентным, что означает, что один и тот же запрос, выполненный один раз, имеет тот же эффект, что и его многократное выполнение подряд, и состояние сервера также остается одинаковым. Другими словами, идемпотентные методы не должны иметь побочных эффектов (кроме статистических целей). При правильной реализации такие методы, как GET, HEAD, PUT и DELETE, являются идемпотентными, а метод POST — нет. Все безопасные методы также идемпотентны.

  • cacheable: Кэшируемый, ответ представляет собой кешируемый ответ HTTP, который сохраняется для последующего извлечения и использования, сохраняя новые запросы на сервере.

пространство ограничено,см. MDN

Заголовки HTTP-запроса

axios предоставляет методы для настройки заголовков HTTP-запросов:

export interface AxiosRequestConfig {
  headers?: any;
}

Заголовок запроса состоит из имени (без учета регистра), за которым следует двоеточие «:», за которым следует конкретное значение (без новой строки). Начальный пробел перед этим значением игнорируется.

Заголовок запроса можно определить как тип заголовка HTTP, который используется в HTTP-запросе и не связан с телом запроса. Некоторые заголовки запросов, такие какAccept, Accept-*, If-*``允许执行条件请求。某些请求头如:Cookie, User-Agentа такжеRefererСам запрос описывается, чтобы гарантировать, что сервер возвращает правильный ответ.

Не все заголовки http, которые появляются в запросах, являются заголовками запросов, например те, которые часто появляются в запросах POST.Content-LengthНа самом деле заголовок объекта, который представляет размер тела запроса, хотя вы также можете назвать его заголовком запроса.

список заголовков сообщений

наборы axios различаются в зависимости от метода запросаContent-Typeа такжеAccpectзаголовок запроса.

установить заголовок запроса

предоставляется объектом XMLHttpRequestXMLHttpRequest对象提供的.setRequestHeader()Этот метод предоставляет разработчикам возможность манипулировать этими двумя данными заголовка и позволяет разработчикам настраивать информацию заголовка заголовка запроса.

XMLHttpRequest.setRequestHeader() — это метод установки заголовка HTTP-запроса. Этот метод должен вызываться между методом open() и send(). Если один и тот же заголовок запроса назначается несколько раз, генерируется только один заголовок запроса с несколькими значениями.

Если свойство Accept не установлено, значение, отправляемое из send(), является значением по умолчанию для этого свойства./. **

В целях безопасности некоторые значения заголовков запросов могут быть установлены только пользовательским агентом: запрещенные имена заголовков и запрещенные имена заголовков ответа.

По умолчанию при отправке AJAX-запроса включаются следующие заголовки:

Код настройки axios выглядит следующим образом:

// 在 adapters 目录下的 xhr.ts 文件中:
if ('setRequestHeader' in requestHeaders) {
  // 通过 XHR 的 setRequestHeader 方法设置请求头信息
  for (const key in requestHeaders) {
    if (requestHeaders.hasOwnProperty(key)) {
      const val = requestHeaders[key];
      if (
        typeof requestData === 'undefined' &&
        key.toLowerCase() === 'content-type'
      ) {
        delete requestHeaders[key];
      } else {
        request.setRequestHeader(key, val);
      }
    }
  }
}

Что касается того, следует ли изменять заголовок http, я предлагаю, конечно, не изменять какое-либо поле по своему желанию.

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

  • Не рекомендуется изменять пользовательский агент небрежно. Есть много веб-сайтов, которые адаптируют контент на основе этого поля. Например, PCS и мобильные телефоны должны иметь разные контент.

  • Некоторые поля можно изменить, напримерconnection,cache-controlЖдать.不会影响你的正常访问,但有可能会慢一点。

  • Есть также некоторые поля, которые можно удалить.Например, если вы не хотите, чтобы веб-сайт записывал ваше поведение при посещении или историческую информацию, вы можете удалить такие поля, как файлы cookie и реферер.

  • Конечно, вы также можете создавать любые поля по своему усмотрению, что обычно не имеет никакого эффекта, если только заголовок не слишком длинный, а содержимое не обрезано. Обычно настраиваемые поля рекомендуется начинать с X-. Например X-тест: копье.

Сводка HTTP

Пока HTTP-запрос отправляется, когда пользователь активно вводит URL-адрес для доступа, эти поля заголовка автоматически генерируются браузером, например, host, cookie, user-agent, Accept-Encoding и т. д. JS может управлять браузером для инициирования запросов, а также может добавлять сюда некоторые заголовки, но, учитывая соображения безопасности и производительности, на возможность JS управлять заголовками, такими как host, cookie, user-agent и т. д., накладываются некоторые ограничения. другие поля.JS необратимИзменены заголовки сообщений.关于 HTTP 的知识实在多,这里简单谈到相关联的知识。这里埋下伏笔,后续若有更适合讲 HTTP 的例子,再延伸。

Следующий CSRF изменит заголовки.

CSRF

Есть три свойства конфигурации, связанные с CSRF:

export interface AxiosRequestConfig {
  xsrfCookieName?: string
  xsrfHeaderName?: string
  withCredentials?: boolean;
}

// 默认配置为
{
  xsrfCookieName: 'XSRF-TOKEN',
  xsrfHeaderName: 'X-XSRF-TOKEN',
  withCredentials: false
}

Итак, кратко разберемсяCSRF

Подделка межсайтовых запросов (английский язык: Подделка межсайтовых запросов), также известная как атака одним щелчком мыши или сеансовая подмена, часто сокращенно CSRF или XSRF, представляет собой метод принуждения пользователя к выполнению непреднамеренных действий на вошедшем в данный момент веб-приложение Метод оперативной атаки. а такжемежсайтовый скриптингПо сравнению с (XSS) XSS использует доверие пользователя к указанному веб-сайту, а CSRF использует доверие веб-сайта к веб-браузеру пользователя.

Что такое CSRF-атака?

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

Принципы CSRF

На своем фишинговом сайте злоумышленник может создать запрос на ваш сайт, создав AJAX-кнопку или форму:

<form action="https://my.site.com/me/something-destructive" method="POST">
  <button type="submit">Click here for free money!</button>
</form>

Чтобы завершить CSRF-атаку, жертва должна последовательно выполнить два шага:

1. Войдите на доверенный веб-сайт А и создайте файл cookie локально.

2. Посетите опасный веб-сайт B, не выходя из системы A.

Как смягчить атаки CSRF?

Используйте только JSON API

Использование JavaScript для инициирования запросов AJAX ограничено в разных доменах. не могу пройти простой<form>отправлятьJSON, поэтому, принимая только JSON, вы можете снизить вероятность этого.

Отключить CORS

Первый способ смягчить CSRF-атаки — отключить перекрестные запросы. Если вы хотите разрешить запросы из разных источников, разрешите толькоOPTIONS, HEAD, GETметоды, потому что они не имеют побочных эффектов. К сожалению, это не блокирует вышеуказанный запрос, поскольку он не использует JavaScript (поэтому CORS не применяется).

Проверьте поле Реферер

В заголовке HTTP есть поле Referer, которое используется для указания адреса, с которого был отправлен запрос. При обработке запросов конфиденциальных данных, как правило, поле Referer должно находиться под тем же доменным именем, что и запрошенный адрес. Этот метод прост и удобен в реализации, требует небольшой рабочей нагрузки и требует добавления только одного шага проверки в критической точке доступа. Но этот подход также имеет свои ограничения, так как он полностью зависит от браузера для отправки правильного поля Referer. Хотя протокол http имеет четкие правила содержания этого поля, он не может гарантировать конкретную реализацию посещающего браузера, а также не может гарантировать, что браузер не имеет уязвимостей безопасности, влияющих на это поле. Также существует вероятность того, что злоумышленники атакуют некоторые браузеры и подделывают их поля Referer. (PS: видно, насколько важно следовать веб-стандартам)

CSRF Tokens

Окончательное решение — использовать токены CSRF. Как работают токены CSRF?

  1. Сервер отправляет токен клиенту.
  2. Форма, отправленная клиентом, содержит этот токен.
  3. Если токен недействителен, сервер отклоняет запрос.

Злоумышленникам нужны какие-то средства для получения токена CSRF вашего сайта, что они могут сделать только с помощью JavaScript. Таким образом, если ваш сайт не поддерживает CORS, у них нет возможности получить токен CSRF, что снижает угрозу.

Убедитесь, что токен CSRF не доступен через AJAX!

не создавайте/CSRFмаршрут для получения токена, особенно не поддерживайте CORS на этом маршруте!

Токен должен быть неугадываемым, что затрудняет его получение злоумышленником после нескольких попыток. Это не должно быть защищено паролем. Атака происходит из-за клика или двух от неизвестного пользователя, а не из-за грубой силы с сервера.

CSRF токены в Axios

вотwithCredentials, сначала понять.

Свойство XMLHttpRequest.withCredentials — это логическое значение, указывающее, следует ли использовать учетные данные, такие как файлы cookie, заголовки авторизации (заголовки авторизации) или сертификаты клиента TLS, для создания запроса управления доступом между сайтами. Использование свойства withCredentials на том же сайте недопустимо.

Если перед отправкой запроса XMLHttpRequest из другого домена для параметра withCredentials не задано значение true, вы не можете установить значение файла cookie для своего собственного домена. Сторонние файлы cookie, полученные путем установки для withCredentials значения true, по-прежнему будут применяться к политике того же источника, поэтому к ним нельзя будет получить доступ через document.cookie или скрипты, запрошенные из заголовка.

// 在标准浏览器环境下 (非 web worker 或者 react-native) 则添加 xsrf 头
if (isStandardBrowserEnv()) {
  // 必须在 withCredentials 或 同源的情况,才设置 xsrfHeader 头
  const xsrfValue =
    (withCredentials || isURLSameOrigin(url)) && xsrfCookieName
      ? cookies.read(xsrfCookieName)
      : undefined;
  if (xsrfValue && xsrfHeaderName) {
    requestHeaders[xsrfHeaderName] = xsrfValue;
  }
}

Резюме CSRF

Для CSRF вам нужно разрешить внутренним учащимся не использовать идемпотенты, такие как get, для конфиденциальных запросов, но поскольку запрос POST, инициированный формой Form, не ограничен CORS, вы можете произвольно использовать файлы cookie из других доменов для отправки в другие домены. POST-запрос для формирования CSRF-атаки.

В настоящее время, если есть запрос, связанный с конфиденциальной информацией, необходимо встретиться с серверной частью студентов, пройти аутентификацию с помощью XSRF-токена. В этом случае мы используем запрос axios, вы можете установитьXMLHttpRequest.withCredentials=trueИ установитьaxios({xsrfCookieName:'',xsrfHeaderName:''}), если не используется, будет использовано значение по умолчаниюXSRF-TOKENа такжеX-XSRF-TOKEN(Вы можете использовать это с бэкэндом).

Поэтому в функции axios клиент поддерживает предотвращение CSRF/XSRF. Просто удобно настраивать CORF-TOKEN, главное поддерживать интерфейс back-end студентов. (PS: Как важно любить друг друга на переднем и заднем концах, поэтому, как на переднем конце, мы должны узнать как можно больше об этом знании.)

Реализация XHR

Axios предоставляет две реализации http и XMLHttpRequest на стороне клиента, которые поддерживают node.js через режим адаптера.В этой статье в основном объясняется реализация XHR.

Примерная логика реализации следующая:

const xhrAdapter = (config: AxiosRequestConfig): AxiosPromise => {
  return new Promise((resolve, reject) => {
    let request: XMLHttpRequest | null = new XMLHttpRequest();
    setHeaders();
    openXHR();
    setXHR();
    sendXHR();
  });
};

Если объяснено построчно, то лучше записать обучающее видео.Рекомендуется смотреть прямо в каталог адаптеров.xhr.ts, есть комментарии в ключевых местах!

  1. xhrAdapter принимает параметры конфигурации (объединенное значение параметра по умолчанию и параметра, передаваемого при его создании пользователем, axios выполняет специальную обработку объединенного значения).
  2. Установить заголовки запроса, например, в соответствии с входящими параметрамиdata,auth,xsrfHeaderNameУстановите соответствующие заголовки
  3. setXHRв основном вrequest.readyState === 4Обработка данных ответа и обработка ошибок при
  4. окончательное исполнениеXMLHttpRequest.sendметод

То, что возвращается, является объектом Promise, поэтому он поддерживает все функции Promise.

запрос на перехват

Перехват запросов в axios следует рассматривать как относительно сложную операцию, а реализация очень проста. Что-то вроде серии промисов, которые выполняются по порядку.

Посмотрите непосредственно на реализацию кода:

  // interceptors 分为 request 和 response。

  interface interceptors {
    request: InterceptorManager;
    response: InterceptorManager;
  }

  request (config: AxiosRequestConfig = {}) {
    const { method } = config
    const newConfig: AxiosRequestConfig = {
      ...this.defaults,
      ...config,
      method: method ? method.toLowerCase() : 'get'
    }

    // 拦截器原理:[请求拦截器,发送请求,响应拦截器] 顺序执行

    // 1、建立一个存放 [ resolve , reject ] 的数组,
    // 这里如果没有拦截器,则执行发送请求的操作。
    // 由于之后都是 resolve 和 reject 的组合,所以这里默认 undefined。真是骚操作!

    const chain = [ dispatchRequest, undefined ]

    // 2、Promise 成功后会往下传递参数,于是这里先传入合并后的参数,供之后的拦截器使用 (如果有的话)。
    let promise: any = Promise.resolve(newConfig)

    // 3、又是一波骚操作,完美的运用了数组的方法。咋不用 reduce 实现 promise 顺序执行呢 ?
    // request 请求拦截器肯定需要 `dispatchRequest` 在前面,于是 [interceptor.fulfilled, interceptor.rejected, dispatchRequest, undefined]
    this.interceptors.request.forEach((interceptor: Interceptor) => {
      chain.unshift(interceptor.fulfilled, interceptor.rejected)
    })
    // response 响应拦截器肯定需要在 `dispatchRequest` 后面,于是 [dispatchRequest, undefined,interceptor.fulfilled, interceptor.rejected]
    this.interceptors.response.forEach((interceptor: Interceptor) => {
      chain.push(interceptor.fulfilled, interceptor.rejected)
    })

    // 4、依次执行 Promise( fulfilled,rejected )
    while (chain.length) {
      promise = promise.then(chain.shift(), chain.shift())
    }

    return promise
  }

Это также идеальное использование базовых знаний, будь то Promise или метод мутации массива, это разумное использование.

Конечно, последовательное выполнение промисов может быть и таким:

function sequenceTasks(tasks) {
  function recordValue(results, value) {
    results.push(value);
    return results;
  }
  var pushValue = recordValue.bind(null, []);
  return tasks.reduce(function(promise, task) {
    return promise.then(task).then(pushValue);
  }, Promise.resolve());
}

отменить запрос

Если вы не знаете, что в XMLHttpRequest есть метод absort, вы наверняка подумаете, что отменить запрос для такого вида операции show невозможно!(PS: насколько важны базовые знания )

const { cancelToken } = config;
const request = new XMLHttpRequest();

if (cancelToken) {
  cancelToken.promise
    .then(cancel => {
      if (!request) {
        return;
      }
      request.abort();
      reject(cancel);
      request = null;
    })
    .catch(err => {
      console.error(err);
    });
}

Что касаетсяCancelTokenНе будем об этом, это странное осознание. Я так и не понял истинного смысла оригинального авторского замысла!

модульный тест

Наконец, когда дело доходит до модульного тестирования, давайте сначала рассмотрим соответствующие зависимости.

используетсяkarma, настроенный следующим образом:

Выполнение заказа:

yarn test

Этот проект основан наjasmineПисать тестовые случаи относительно просто.

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

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

Суммировать

Благодаря друзьям, которые могут видеть здесь, я также должен быть поклонником TypeScript или Axios, давайте познакомимся.

Опять же, TypeScript действительно прост в использовании. Axios можно грубо отрефакторить за короткое время, и те, кто заинтересован, могут следовать за ним. Это старое правило, я не буду подробно рассказывать о том, как пользоваться библиотекой в ​​шаринге (видимо, если вы сами допилите такой проект, вам не стоит смотреть на API.), а больше для расширения кругозора каждого. точки знания из широты. Если вы новичок в определенном ключевом слове, пришло время улучшить его. Например, далее автор собирается углубиться в HTTP. Хотя, похоже, текущая популярность TypeScript не очень высока. Хорошие вещи всегда те, которые нелегко изменить. Ха, не бей тебя по лицу.

Я стал сильнее? Перестань говорить, слушать Ян Zongwei "Я изменился, я не изменился".

Помните, что нет ошибок, которые нельзя решить, просмотрев исходный код.

Ссылаться на