Что на самом деле не так с конечной точкой, возвращающей HTML, а не данные JSON?

77

Когда я впервые начал изучать PHP (около 5 или 6 лет назад), я узнал об Ajax и прошел «фазы»:

  1. Ваш сервер возвращает данные HTML, и вы помещаете их в innerHTML DOM
  2. Вы узнаете о форматах передачи данных, таких как XML (и говорите «ооо, значит, для этого он и используется»), а затем JSON.
  3. Вы возвращаете JSON и создаете свой пользовательский интерфейс, используя ванильный код JavaScript
  4. Вы переходите в JQuery
  5. Вы узнаете об API, заголовках, кодах состояния HTTP, REST , CORS и Bootstrap
  6. Вы изучаете SPA и среды интерфейса ( React , Vue.js и AngularJS ) и стандарт JSON API.
  7. Вы получаете корпоративный устаревший код и, осмотрев его, обнаружите, что они делают то, что описано в шаге 1.

Работая с этой унаследованной кодовой базой, я даже не думал, что она может возвращать HTML (я имею в виду, мы теперь профессионалы, верно?), Поэтому мне было трудно искать конечную точку JSON, которая возвращала бы данные, которые Аякс призывает заселять. Только когда я спросил «программиста», он сказал, что он возвращает HTML и добавляется непосредственно в DOM с помощью innerHTML.

Конечно, это было трудно принять. Я начал думать о способах рефакторинга этого в конечные точки JSON, думал о модульном тестировании конечных точек и так далее. Однако эта кодовая база не имеет тестов. Ни одного. И это более 200 тысяч строк. Конечно, одна из моих задач включает в себя предложение подходов для тестирования всего этого, но на данный момент мы еще не занимаемся этим.

Так что я нигде в углу не задумываюсь: если у нас нет никаких тестов, то у нас нет особой причины для создания этой конечной точки JSON (поскольку она не «повторно используется»: она буквально возвращает данные, которые помещаются только в эту часть приложение, но я думаю, что это уже подразумевалось, поскольку он ... возвращает данные HTML).

Что именно не так с этим?

Кристофер Франциско
источник
3
Также связано: stackoverflow.com/questions/1284381/… <- очень хороший ответ в SO.
Мачадо
73
Сервер, использующий HyperText Transfer Protocol, возвращающий HyperText ?! Ужас!
Энди
3
@ Andy Честно говоря, на самом деле это общий протокол передачи сообщений: в нем нет ничего особенного для передачи гипертекста, в отличие от FTP, который много говорит о вещах, специфичных для файлов и каталогов.
Joker_vD
4
@Joker_vD Я никогда не слышал о протоколе под названием GMTP. В то время как вещи развивались, и вы можете отправлять другие типы контента по HTTP, это не было первоначальной целью. Я хочу сказать, что только потому, что вы можете отправлять другой контент, кроме гипертекста, используя HTTP, кажется глупым предполагать, что его использование больше не подходит для его первоначальной цели.
Энди

Ответы:

114

Что на самом деле не так с конечной точкой, возвращающей HTML, а не данные JSON?

Не важно. Каждое приложение имеет свои требования, и может случиться так, что ваше приложение не было разработано как SPA.

Может случиться так, что эти прекрасные фреймворки, которые вы цитировали (Angular, Vue, React и т. Д.), Не были доступны во время разработки или не были «одобрены» корпоративными вещами для использования в вашей организации.

Я скажу вам следующее: конечная точка, которая возвращает HTML, уменьшает вашу зависимость от библиотек JavaScript и снижает нагрузку на браузер пользователя, поскольку не нужно интерпретировать / выполнять код JS для создания объектов DOM - HTML уже есть, это просто вопрос анализа элементов и их рендеринга. Конечно, это означает, что мы говорим о разумном количестве данных. 10 мегабайт данных HTML не является разумным.

Но так как нет ничего плохого в возврате HTML, то, что вы теряете, не используя JSON / XML, это в основном возможность использования вашей конечной точки в качестве API. И здесь лежит самый большой вопрос: действительно ли это должен быть API?

Связано: нормально ли возвращать HTML из JSON API?

Мачадо
источник
4
Я бы сделал шаг назад, прежде чем сказать, что это просто «просто предпочтение». Есть некоторые «важные решения», которые вы должны принять: это API или нет, у меня есть соответствующие библиотеки для работы с данными JSON на клиенте, какой тип клиента я буду поддерживать (браузеры без Javascript, для пример), какой объем и процессорное время у меня есть в наличии, какую стратегию мои программисты будут использовать лучше и т. д. и т. д. и т. д.
Machado
7
«Не нужно интерпретировать код JS для создания объектов DOM - объекты DOM уже есть, это просто вопрос их рендеринга» - ну, HTML уже есть (как только он поступит по проводам). Браузер должен проанализировать HTML и сделать из него объекты DOM.
Пол Д. Уэйт,
7
Нет никаких причин, по которым HTML не может выступать в качестве API. Нуль. Никто. Фактически, HAL + JSON и HAL + XML имеют поразительное сходство с HTML. Вот отличный разговор о REST. Соответствующая часть о возврате HTML из конечной точки близка к концу. youtu.be/pspy1H6A3FM Лично я заставляю все мои конечные точки возвращать как json, так и HTML. Если вы пишете обнаруживаемые сервисы, вы можете легко просматривать их в ... задыхающемся ... браузере.
RubberDuck
4
Потому что это полная сучка для извлечения данных, которые вам действительно нужны, чтобы попытаться использовать их любым новым способом?
DeadMG
4
Обслуживание HTML через HTTP? Что это? Сайт?
Ant P
50

JSON и HTML выполняют две разные семантические цели.

Если вы заполняете веб-страницу данными, используйте JSON. Если вы создаете веб-страницу из частей веб-страниц, используйте HTML.

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

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

Роберт Харви
источник
1
«Во-первых, когда вы создаете часть веб-страницы с использованием HTML, вы работаете на стороне сервера». Почему? Я не вижу причин, почему это должно быть так. Это очевидно только для начальной загрузки страницы и, возможно, даже тогда, когда клиент может делать запросы на данные, которые ему нужны.
DeadMG
3
@DeadMG Должно быть сказано «когда вы создаете часть веб-страницы с использованием HTML, возвращаемого сервером» (в отличие от использования JSON, возвращаемого сервером)
user253751
На самом деле, но так как мотивация для этого невелика, я не вижу в этом смысла.
DeadMG
6
@DeadMG Мало мотивации на то, что когда-либо будет иметь место? Для сервера вернуть HTML? Это буквально то, о чем весь этот вопрос SE.
user253751
Вопрос в том, стоит ли возвращать HTML. Понятно, что первоначальным ответом должен быть HTML, но нет никаких очевидных причин, по которым любые другие API должны возвращать HTML.
DeadMG
22

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

Возврат простых данных и разрешение клиенту рендеринга уменьшает связность и повышает гибкость и тестируемость - вы можете запускать модульные тесты на клиенте для ложных данных и запускать модульные тесты на сервере для проверки нужных данных.

DeadMG
источник
11
HTML можно сделать достаточно общим. Например, вы можете вернуть маркированный список и поместить его в div, где он будет подвергаться стилизации с помощью преобладающего CSS.
Роберт Харви
10
Это не так уж и полезно, если на этот раз мне нужно набить это. Или сделать это в другом приложении, которое не отображается в HTML.
DeadMG
2
Я бы перефразировал, как всегда будет составлять HTML, и форма этого HTML всегда должна быть полностью согласованной во всех случаях, что не является очень полезной гарантией. Например, в нашем приложении мы имеем списки, но мы на самом деле не использовали ulи , liно вместо того, чтобы изменилось , чтобы сделать каждый из них на div(не помню , почему). Было бы сложно, если бы сервер возвратил кучу HTML с uls и lis в нем.
DeadMG
2
Кажется бессмысленным получать гарантию, во-первых, когда вы можете просто вернуть данные и позволить клиенту отобразить их в виде HTML, как он сочтет нужным (если он вообще собирается их отображать)
DeadMG
1
Единственный сценарий, который я могу видеть, где возвращение HTML было бы предпочтительным, - это если у клиента недостаточно ресурсов для выполнения самого рендеринга.
DeadMG
14

Я думаю, что у вас есть немного назад. Ты говоришь:

у нас нет никакого теста, поэтому у нас нет особой причины для создания этой конечной точки JSON

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

200 тыс. Строк кода - это много для рефакторинга, и, вероятно, его сложно поддерживать. Хорошее место для начала может быть определение некоторых конечных точек и их тестирование.

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

Виктор Санд
источник
Смысл изменений макета звучит скорее как необходимость отделить шаблоны от базовых данных, но нет причин, по которым эти шаблоны должны быть на клиенте. На самом деле, есть множество причин, по которым они не должны этого делать, например, вы не можете решить скрыть данные от клиента, если ваш рендеринг выполняется на клиенте. Частицы HTML могут быть перезаписаны просто отлично, если они выводятся той же системой шаблонов, что и полные страницы HTML.
IMSoP
6

Есть 3 способа (по крайней мере?) Для создания веб-страницы:

  • Генерация всей страницы на стороне сервера.
  • Верните голую страницу с сервера и кода (JavaScript), и пусть страница извлечет свои данные и отобразит их на стороне клиента HTML.
  • Возвратите частичную страницу плюс код и получите код, извлекающий предварительно отрендеренные блоки HTML, которые он может перетаскивать на страницу.

Первый в порядке. Второй тоже хорошо. Это последняя проблема.

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

Дело в том, что теперь вы разделили знания, которые должны быть централизованы в одном месте (а именно, логику представления), и это затрудняет проверку правильности совмещения всех частей. Используя JSON API, вы можете вместо этого хранить всю эту логику только во внешнем интерфейсе, или же вы можете хранить все это в своих шаблонах на стороне сервера, если сначала вы переводите свои данные в HTML. Речь идет о хранении презентационных знаний / логики в одном месте, чтобы ими можно было управлять последовательно и как часть единого процесса. HTML / CSS / JS достаточно сложен, чтобы не усложнять, не разбивая его на множество мелких частей.

API-интерфейсы JSON также имеют дополнительное преимущество, заключающееся в том, что данные доступны полностью независимо от логики представления. Это позволяет нескольким различным докладчикам, таким как мобильное приложение и веб-страница, использовать одни и те же данные. В частности, он позволяет использовать данные без браузера (например, мобильные приложения или ночные задания cron); эти потребители могут даже не иметь возможности разбирать HTML. (Это, конечно, обязательно зависит от ситуации, когда данные у разных потребителей совпадают, или один может использовать подмножество другого.) Необходимость этой возможности зависит от требований конкретного приложения, хотя при управлении презентацией логика нужна вне зависимости Я скажу, что если вы начнете реализовывать это заранее, вы будете лучше подготовлены к будущему росту.

jpmc26
источник
2
Я на самом деле думаю, что избегание дублирования логики отображения может быть хорошей причиной для рендеринга фрагментов HTML-страницы: если вы отрисовываете часть страницы на сервере (например, заголовок и базовый макет), а затем генерируете другие части на основе данных JSON на клиенте, вы есть два разных набора шаблонов. Рендеринг партиалов на сервере перемещает эту логику обратно на уровень центрального представления, который может использовать тот же шаблон для рендеринга отдельного компонента, как если бы он статически собирал всю страницу.
IMSoP
1
ты единственный, кто упоминает мобильный, я хочу дать вам тысячу upvotes для этого
Lovis
1
@IMSoP Если вам нужна динамическая страница, у вас должна быть логика внешнего интерфейса. Если вы по-прежнему визуализируете фрагменты на стороне сервера, теперь вы должны убедиться, что предположения внешнего интерфейса соответствуют предварительным условиям сервера, создающего фрагменты. Вы не можете сломать эту зависимость. Синхронизировать эти знания сложнее, если они разделены на полностью разделенные системы. Если вы просто визуализируете на переднем конце, эти предположения централизованы. Я думаю, что я бы также избегал смешивать динамический интерфейс с начальным состоянием в шаблоне на стороне сервера; «Начальная загрузка» для запуска внешнего интерфейса проще.
jpmc26
4

Я бы сказал, что нет ничего плохого в том, что сервер возвращает HTML-фрагмент и пользовательский интерфейс, присваивающий его .innerHTML некоторого элемента. На мой взгляд, это самый простой способ разработки асинхронного кода JavaScript. Преимущество заключается в том, что с помощью JavaScript делается как можно меньше, а в управляемой серверной среде - как можно больше. Помните, что поддержка JavaScript в браузерах варьируется, но ваш бэкэнд всегда имеет одну и ту же версию бэкэнд-компонентов, что означает, что выполнение как можно большего количества бэкэнда будет означать как можно меньше несовместимостей версий.

Теперь иногда вы хотите больше, чем просто фрагмент HTML. Например, код состояния и фрагмент HTML. Затем вы можете использовать объект JSON, имеющий два члена, statusCode и HTML, второй из которых может быть назначен .innerHTML какого-либо элемента после проверки statusCode. Таким образом, использование JSON и использование innerHTML отнюдь не являются альтернативными эксклюзивными подходами; они могут быть использованы вместе.

Используя JSON, вы даже можете иметь несколько фрагментов HTML в одном ответе, которые присваиваются .innerHTML нескольких элементов.

В итоге: используйте .innerHTML. Это делает ваш код совместимым с максимально возможным количеством версий браузера. Если вам нужно больше, используйте JSON и .innerHTML вместе. Избегайте XML.

juhist
источник
4

Нет ничего плохого в принципе . Вопрос в том, чего вы хотите достичь?

JSON идеально подходит для передачи данных. Если вы вместо этого отправляете HTML и ожидаете, что клиент извлечет данные из HTML, то это чушь.

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

И только вчера я столкнулся с кодом, который помещает два элемента в массив, превратил массив в JSON, поместил JSON в строку, поместил строку в массив, превратил весь массив в JSON, отправил его клиенту, который декодировал JSON, получил массив, содержащий строку, взял строку, извлек JSON из строки, декодировал JSON и получил массив с двумя элементами. Не делай этого.

gnasher729
источник
+1 Точно. Первый вопрос: что нужно получить? Было бы немного неправильно с конечной точкой, возвращающей рекламу на боковой панели в виде фрагмента HTML, или, возможно, нижнего колонтитула или подобных элементов.
SQB
3

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

В современном приложении код API должен отвечать за данные, а код клиента должен отвечать за представление.

Когда ваш API возвращает HTML, вы тесно связываете свои данные и представление. Когда API возвращает HTML, единственное, что вы можете (легко) сделать с этим HTML, это отобразить его как некоторую часть большей страницы. С другой стороны, единственное, для чего хорош API - это обеспечение вашей страницы HTML. Кроме того, вы распространили свой HTML-код как на клиентский, так и на серверный код. Это может сделать обслуживание головной болью.

Если ваш API возвращает JSON или какую-либо другую форму чистых данных, это становится намного более полезным. Существующее приложение может по-прежнему использовать эти данные и представлять их соответствующим образом. Теперь другие вещи могут использовать API для доступа к тем же данным. Опять же, обслуживание проще: весь HTML-код находится в одном месте, поэтому, если вы хотите изменить стиль всего сайта, вам не нужно менять свой API.

SouthShoreAK
источник
5
«В современном приложении код API должен отвечать за данные, а код клиента должен отвечать за представление». Почему так должно быть всегда? Я согласен с тем, что это обычная модель и что она облегчает определенные вещи, но я не вижу причин поднимать ее до уровня «должен» ... Это решение, которое необходимо принимать в каждом конкретном случае, и, конечно, есть причины, по которым в некоторых ситуациях вы можете принять другое решение.
Жюль
@Jules, потому что, если у вас есть API и клиент, то и то, и другое отвечает за рендеринг, является нарушением разделения интересов. (Теперь у вас не обязательно есть API и клиент. У вас может быть только один компонент, и он будет выполнять всю презентацию. Но тогда у вас нет API)
njzk2
@ njzk2 То, что API доставляет данные HTML, не означает, что они их отображали. Например, он может обрабатывать HTML как большой двоичный объект и хранить его в базе данных. Кроме того, некоторая визуализация может потребоваться на сервере, а не на клиенте (например, предоставление статических страниц для поисковых систем), поэтому повторное использование этой возможности может рассматриваться как устранение дублирования.
Жюль
1
Кроме того, вполне возможно создать клиентскую и api-пару, где весь рендеринг происходит на сервере, а клиент просто подключает доставленный HTML-код в предопределенные слоты в своем DOM. У Jquery есть целый модуль, посвященный клиенту такого типа, который предполагает, что они должны быть достаточно распространенными.
Жюль
1
@ Джулс много чего достаточно распространенного, это не причина, почему они разумны.
njzk2
2

HTML привязан к конкретному дизайну и использованию.

С HTML, если вы хотите изменить макет страницы, вам нужно изменить способ генерации HTML при вызове сервера. Обычно для этого требуется программист. Теперь у вас есть back-end программисты, которые по определению не являются вашими лучшими авторами html-файлов и обрабатывают эти обновления.

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

Кроме того, JSON может стать основой для других сервисов. У вас могут быть разные роли, которым нужно по-разному просматривать одни и те же основные данные. Например, у вас может быть веб-сайт клиента, который показывает данные о продукте на странице заказа, и внутренняя страница продаж для представителей, которая показывает те же данные в совершенно ином макете, возможно, наряду с некоторой другой информацией, недоступной для обычных клиентов. С JSON один и тот же серверный вызов может использоваться в обоих представлениях.

Наконец, JSON может масштабироваться лучше. В последние годы мы как бы перешли на сторону клиентских JavaScript-фреймворков. Я думаю, что пришло время сделать шаг назад и начать думать о том, какой javascript мы используем, и как это влияет на производительность браузера ... особенно на мобильных устройствах. Тем не менее, если вы используете сайт, достаточно большой, чтобы требовать серверную ферму или кластер, вместо одного сервера, JSON может масштабироваться лучше. Пользователи бесплатно дадут вам время обработки в своих браузерах, и если вы воспользуетесь этим, вы сможете уменьшить нагрузку на сервер при большом развертывании. JSON также использует меньшую пропускную способность, поэтому, если вы достаточно большойи использовать его надлежащим образом, JSON заметно дешевле. Конечно, он также может масштабироваться хуже, если вы в конечном итоге будете загружать 40 КБ библиотеки для анализа 2 КБ данных в 7 КБ HTML, и снова: платите, чтобы быть в курсе того, что вы делаете. Но у JSON есть потенциал для повышения производительности и затрат.

Джоэл Коухорн
источник
1

Нет ничего плохого в такой конечной точке, если она выполняет свои требования. Если требуется выложить html, который известный потребитель может эффективно проанализировать, конечно, почему бы и нет?

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

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

Теперь, если вы убедитесь, что ваш html-код соответствует XML-формату, значит, вы - золото.

С учетом сказанного, у меня есть существенная проблема с этим:

Я скажу вам следующее: конечная точка, которая возвращает HTML, уменьшает вашу зависимость от библиотек JavaScript и снижает нагрузку на пользовательский браузер, так как ей не нужно интерпретировать / выполнять код JS для создания объектов DOM - HTML уже есть, это просто вопрос анализа элементов и их рендеринга. Конечно, это означает, что мы говорим о разумном количестве данных. 10 мегабайт данных HTML не является разумным.

Это плохая идея, независимо от того, как вы ее обрезаете. Десятилетия коллективного промышленного опыта показали нам, что, в целом, хорошая идея отделить данные (или модель) от их отображения (или представления).

Здесь вы объединяете их с целью быстрого выполнения кода JS. И это микрооптимизация.

Я никогда не считал это хорошей идеей, за исключением очень тривиальных систем.

Мой совет? Не делай этого. ХК СВНТ, ДРАКОНЫ , YMMV и др.

luis.espinal
источник
0

JSON - это просто текстовое представление структурированных данных. Клиент, естественно, должен иметь парсер для обработки данных, но практически все языки имеют функции парсера JSON. Гораздо эффективнее использовать парсер JSON, чем парсер HTML. Это занимает мало места. Не так с парсером HTML.

В PHP вы просто используете, json_encode($data)и клиент на другой стороне может его проанализировать. А когда вы извлекаете данные JSON из веб-службы, вы просто используете $data=json_decode($response)и можете решить, как использовать данные, как если бы вы использовали переменные.

Предположим, вы разрабатываете приложение для мобильного устройства. Зачем вам нужен формат HTML, когда мобильные приложения редко используют веб-браузер для анализа данных? Многие мобильные приложения используют JSON (наиболее распространенный формат) для обмена данными.

Учитывая то, что мобильные телефоны часто строятся по разным тарифам, почему вы хотите использовать HTML, который требует гораздо большей пропускной способности, чем JSON?

Зачем использовать HMTL, когда HTML ограничен в своем словаре, а JSON может определять данные? {"person_name":"Jeff Doe"}более информативен, чем HTML может предоставить о своих данных, поскольку он определяет только структуру для анализаторов HTML, но не определяет данные.

JSON не имеет ничего общего с HTTP. Вы можете поместить JSON в файл. Вы можете использовать его для конфигурации. Композитор использует JSON. Вы также можете использовать его для сохранения простых переменных в файлах.

netrox
источник
0

Трудно классифицировать правильное или неправильное. ИМО, я задам следующие вопросы: « Должно ли это » или « может ли это быть меньше? ».

Каждая конечная точка должна стремиться к общению с как можно меньшим количеством контента. Отношение сигнал / шум обычно составляет HTTP-коды <JSON <XHTML. В большинстве ситуаций лучше выбрать наименее шумный протокол.

Я не согласен с вопросом о загрузке клиентского браузера @machado, так как в современных браузерах это не проблема. Большинство из них достаточно хорошо работают с HTTP-кодами и ответами JSON. И хотя в данный момент у вас нет тестов, долгосрочное обслуживание менее шумного протокола будет дешевле, чем над ним.

опасный
источник