Небольшая статья о том, как мы столкнулись с проблемами синхронизации работы команд разработчиков клиента и сервера.
Как мы подключили Thrift, чтобы упростить общение между нашими командами.
Кому интересно, как мы это сделали, и с какими «побочными» эффектами столкнулись, прошу заглянуть под кат.
Фон
В начале 2017 года, когда мы запускали новый проект, в качестве фронтенда мы выбрали EmberJS. Что практически автоматически привело нас к работе по схеме REST при организации взаимодействия клиентской и серверной частей приложения.Потому что EmberData предоставляет удобный инструмент разделения работы бэкенд- и фронтенд-команды, а использование Адаптера позволяет выбрать «протокол» взаимодействия.
Поначалу всё было хорошо — Ember предоставил нам возможность реализовать эмуляцию запросов к серверу.
Данные для эмуляции серверных моделей были размещены в отдельных файлах фьючерсов.
Если мы начали где-то работать без использования Ember Data, то Ember позволяет нам написать рядом эмулятор обработчика конечной точки и вернуть эти данные.
У нас было соглашение, что разработчики серверной части должны вносить изменения в эти файлы, чтобы поддерживать актуальность данных, чтобы разработчики внешнего интерфейса могли работать правильно.
Но, как всегда бывает, когда все основано на «договоренностях» (а инструмента их проверки нет), наступает момент, когда «что-то идет не так».
Новые требования привели не только к появлению новых данных на клиенте, но и к обновлению старой модели данных.
Что в конечном итоге привело к тому, что поддерживать синхронность моделей на сервере и ее эмуляцию в исходном коде клиента стало просто дорого.
Сейчас разработка клиентской части, как правило, начинается после того, как готова серверная заглушка.
А разработка ведется поверх производственного сервера, что усложняет командную работу и увеличивает время выпуска нового функционала.
Разработка проекта
Сейчас мы отказываемся от EmberJS в пользу VueJS. и в рамках решения о миграции мы начали искать варианты решения этой проблемы.Были разработаны следующие критерии:
- Совместимость со старыми и новыми версиями протокола.
- Максимальное удобство для фронтенд-разработчиков при работе «без сервера»
- Отделение описания API от тестовых данных
- Простая синхронизация подписи звонков
- четкое описание подписи
- простота модификации как внешними, так и внутренними разработчиками
- максимальная автономность
- Желательно использовать строго типизированный API. Те.
максимально быстрое обнаружение изменений протокола
- Простота тестирования логики сервера
- Интеграция со Spring на серверной стороне без танцев с бубнами.
Выполнение
Подумав было решено остановиться на Бережливость .Это дало нам простой и понятный язык описания API.
Для связи мы используем TMultiplexedProcessor, доступный через TServlet, используя TJSONProtocol. Мне пришлось немного потанцевать, чтобы этот Thrift легко интегрировался со Spring. Для этого мне пришлось программно создать и зарегистрировать сервлет в ServletContainer.namespace java ru.company.api namespace php ru.company.api namespace javascrip ru.company.api const string DIRECTORY_SERVICE= "directoryService" exception ObjectNotFoundException{ } struct AdvBreed { 1: string id, 2: string name, 3: optional string title } service DirectoryService { list<AdvBreed> loadBreeds() AdsBreed getAdvBreedById(1: string id) }
@Component
class ThriftRegister : ApplicationListener<ContextRefreshedEvent>,
ApplicationContextAware, ServletContextAware {
companion object {
private const val unsecureAreaUrlPattern = "/api/v2/thrift-ns"
private const val secureAreaUrlPattern = "/api/v2/thrift"
}
private var inited = false
private lateinit var appContext:ApplicationContext
private lateinit var servletContext:ServletContext
override fun onApplicationEvent(event: ContextRefreshedEvent) {
if (!inited) {
initServletsAndFilters()
inited = true
}
}
private fun initServletsAndFilters() {
registerOpenAreaServletAndFilter()
registerSecureAreaServletAndFilter()
}
private fun registerSecureAreaServletAndFilter() {
registerServletAndFilter(SecureAreaServlet::class.java,
SecureAreaThriftFilter::class.java, secureAreaUrlPattern)
}
private fun registerOpenAreaServletAndFilter() {
registerServletAndFilter(UnsecureAreaServlet::class.java,
UnsecureAreaThriftFilter::class.java, unsecureAreaUrlPattern)
}
private fun registerServletAndFilter(servletClass:Class<out Servlet>,
filterClass:Class<out Filter>, pattern:String) {
val servletBean = appContext.getBean(servletClass)
val addServlet = servletContext.addServlet(servletClass.simpleName, servletBean)
addServlet.setLoadOnStartup(1)
addServlet.addMapping(pattern)
val filterBean = appContext.getBean(filterClass)
val addFilter = servletContext.addFilter(filterClass.simpleName, filterBean)
addFilter.addMappingForUrlPatterns(null, true, pattern)
}
override fun setApplicationContext(applicationContext: ApplicationContext) {
appContext = applicationContext
}
override fun setServletContext(context: ServletContext) {
this.servletContext = context
}
}
Что здесь следует отметить? Этот код создает две области обслуживания.
Protected, который доступен по адресу «/api/v2/thrift».
И открыть, доступный по адресу «/api/v2/thrift-ns».
Для этих областей используются разные фильтры.
В первом случае при доступе к сервису с использованием файлов cookie генерируется объект, идентифицирующий пользователя, совершающего вызов.
Если сгенерировать такой объект невозможно, выдается ошибка 401, которая корректно обрабатывается на стороне клиента.
Во втором случае фильтр пропускает все запросы к сервису, и если определяет, что авторизация произошла, то после завершения операции наполняет куки необходимой информацией, чтобы можно было делать запросы в защищенную область.
Чтобы подключить новую услугу, вам придется написать немного дополнительного кода.
@Component
class DirectoryServiceProcessor @Autowired constructor(handler: DirectoryService.Iface):
DirectoryService.Processor<DirectoryService.Iface>(handler)
И зарегистрировать процессор @Component
class SecureMultiplexingProcessor @Autowired constructor(dsProcessor: DirectoryServiceProcessor) : TMultiplexedProcessor() {
Теги: #java #vue.js #Kotlin #spring #thrift
-
Квик Бакс Против. Закладываем Основу
19 Oct, 24 -
Glpi + Fusion Inventory
19 Oct, 24 -
Википедия Добавлена В Google Maps
19 Oct, 24 -
Подкаст Unclesosky - Эпизод №21
19 Oct, 24