Я работал над проектом FeathersJS, который использовал реальное время на веб-клиенте, во время проверки производительности мы искали, что можно удалить, что не было необходимо для уменьшения размеров пакетов ядра / поставщика. Поскольку реальное время не использовалось для сообщений или обновлений в реальном времени, это было относительно очевидное место для поиска.

Используя FeathersJS в течение нескольких лет, я подумал, что это будет относительно простое изменение, даже несмотря на то, что я сам еще не менял клиентские транспорты в проекте и фактически использовал реальное время для большинства проектов, которые у меня есть. Само изменение кода, как и ожидалось, было довольно простым: установить новые клиентские библиотеки для REST и установить node-fetch, так как это было приложение с рендерингом на стороне сервера.

Проблемы начинаются

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

Проблемы с массивом

У нас были довольно сложные запросы, которые имели множество глубоко вложенных параметров, которые затем использовались в ловушке для создания ассоциаций, которые отлично работали с запросами через веб-сокеты, но полностью не работали при использовании REST. Изучив, как FeathersJS анализирует строку запроса, я обнаружил, что он использовал пакет querystring, у которого была возможность увеличить глубину анализа вложенной строки. По умолчанию он будет анализировать только до 5 дочерних элементов в глубину, что было проблемой, поскольку у нас были более глубокие запросы. Вот что произошло бы, если бы у вас был запрос с глубиной более 5 дочерних элементов:

const input = 'a[b][c][d][e][f][g][h][i]=j'
const output = {
    a: {
        b: {
            c: {
                d: {
                    e: {
                        f: {
                            '[g][h][i]': 'j'
                        }
                    }
                }
            }
        }
    }
}

Решение для массива

Решение выделено в разделе часто задаваемые вопросы, где вы можете установить собственный qs экземпляр с вашими собственными параметрами. Это позволяет вам настроить глубину анализа строки запроса:

// Update limits for `qs` to allow for deeper
// parsing of objects specifically from REST
app.set('query parser', function (str) {
  return qs.parse(str, {
    arrayLimit: 100,
    depth: 20,
    parameterLimit: 2000
  });
});

нулевой вопрос

Следующая проблема, которая также появляется в часто задаваемых вопросах, заключается в том, что значение null, когда в запросе, отправляемом через REST, не обрабатывается правильно, оно будет отображаться как пустая строка. Это не работает при использовании Sequelize с postgres, поскольку значение null обычно превращается в 'property' is not null запрос, который в итоге оказывается 'property' != ''.

нулевое решение

Для правильной обработки null мы должны просмотреть документацию по API библиотеки qs. Мы видим, что есть возможность разрешить strictNullHandling, которую мы можем добавить к query parser сервера, как мы установили выше.

// Allow for strict null handling
app.set('query parser', function (str) {
  return qs.parse(str, {
    arrayLimit: 100,
    depth: 20,
    parameterLimit: 2000,
    strictNullHandling: true
  });
});

Теперь проблема в том, как установить, как библиотека qs ведет себя на клиенте, когда она вызывает qs.stringify для объекта запроса? Что ж, в настоящее время это невозможно, нет способа передать параметры qs.stringify через клиент FeathersJS rest, а также нет способа, который позволил бы вам расширить и настроить способ создания строки запроса.

Но не бойтесь, у меня есть пиар, который решит эту проблему. Первоначально я создал PR для возможности добавлять параметры для этого эффекта, но после короткого обсуждения и дополнительной информации от Дэвида, основного разработчика FeathersJS, было решено, что разрешение расширяемости предпочтительнее опций, поэтому был сделан новый PR, чтобы сделать это возможно. Это позволит сделать следующее:

import feathers from '@feathersjs/feathers'
import rest from '@feathersjs/rest-client'
import { FetchClient } from '@feathersjs/rest-client'
import qs from 'qs'

const app = feathers()
​
class MyFetchClient extends FetchClient {
  getQuery (query) {
    if (Object.keys(query).length !== 0) {
      const queryString = qs.stringify(query, {
        strictNullHandling: true
      })

      return `?${queryString}`
    }

    return ''
  }
}
​
// Configure API url
const restClient = rest('https://feathers-api.com')
​
// Configure rest client 
app.configure(restClient.fetch(window.fetch, MyFetchClient))

С учетом этих изменений местами это обеспечивает более плавный переход между REST и веб-клиентами реального времени для FeathersJS API.

Первоначально опубликовано на https://mattchaffe.uk.