终结点返回HTML而不是JSON数据实际上有什么问题?


77

当我刚开始学习PHP时(大约5或6年前),我了解了Ajax,并且经历了“阶段”:

  1. 您的服务器返回HTML数据,并将其放入DOM的 innerHTML中
  2. 您将了解诸如XML之类的数据传输格式(然后说“噢,这就是它的用途”),然后是JSON。
  3. 您返回JSON并使用原始JavaScript代码构建UI
  4. 您移至jQuery
  5. 您将了解API,标头,HTTP状态代码,RESTCORSBootstrap
  6. 您将学习SPA和前端框架(ReactVue.jsAngularJS)以及JSON API标准。
  7. 您会收到一些企业旧代码,并在对其进行检查后发现它们执行了步骤1中所述的操作。

当我使用此旧版代码库时,我什至都不认为它可以返回HTML(我的意思是,我们现在是专业人员,对吗?),所以我很难寻找要返回数据的JSON端点。 Ajax调用会填充。直到我问“程序员”,他才告诉我它正在返回HTML,并使用innerHTML直接附加到DOM。

当然,这很难接受。我开始考虑将其重构为JSON端点的方法,并考虑对端点进行单元测试等等。但是,此代码库没有测试。没有一个。超过20万行。当然,我的任务之一是提出测试整个事物的方法,但是目前我们还没有解决。

因此,我无处不在,想知道:如果我们没有任何测试,那么就没有创建此JSON端点的特殊理由(因为它不是“可重用的”:它从字面上返回仅适合该部分的数据)应用程序,但是我认为这已经隐含了,因为它返回HTML数据)。

什么究竟是错这样做呢?



3
也相关:stackoverflow.com/questions/1284381/… <-SO中的一个很好的答案。
马查多

73
使用超文本传输​​协议的服务器返回超文本?惊恐的事件!
安迪

3
@Andy说实话,它实际上是通用消息传输协议:与FTP相对,它与传输超文本无关,FTP讨论了很多有关文件和目录的特定问题。
Joker_vD

4
@Joker_vD我从未听说过一种称为GMTP的协议。事情发展了,您可以通过HTTP发送其他类型的内容,但这并不是最初的意图。我的观点是,仅仅因为您可以使用HTTP发送超文本之外的其他内容,所以建议将其用于其原始用途不再有效,这似乎很愚蠢。
安迪

Answers:


114

终结点返回HTML而不是JSON数据实际上有什么问题?

真的没什么。每个应用程序都有不同的要求,可能不是您的应用程序设计为SPA。

可能是您引用的这些漂亮框架(Angular,Vue,React等)在开发时不可用,或者未在组织中使用“批准的”企业事物。

我要告诉你的是:返回HTML的端点减少了您对JavaScript库的依赖,并减轻了用户浏览器的负担,因为它不需要解释/执行JS代码来创建DOM对象-HTML已经存在,只需解析元素并渲染它们即可。当然,这意味着我们在谈论合理数量的数据。10 MB的HTML数据是不合理的。

但是,由于返回HTML没什么问题,因此,不使用JSON / XML所造成的损失基本上就是将端点用作API的可能性。这是最大的问题:它真的需要成为API吗?

相关:是否可以从JSON API返回HTML?


4
在说这只是“简单地选择”之前,我要退后一步。您需要做出一些“大问题”的决定:是否是API,我是否有适当的库可以作为客户端上的JSON数据来使用,我将支持哪种类型的客户端(没有Javascript的浏览器,用于例如),我可以使用多少容量与CPU时间,我的程序员将使用哪种策略更好地利用,等等。等等
Machado

7
“它不需要解释JS代码就可以创建DOM对象-DOM对象已经存在,只需渲染它们即可。”-嗯,HTML已经存在(一旦通过电线到达)。浏览器必须解析HTML并从中创建DOM对象。
Paul D. Waite

7
HTML不能充当API的理由是零。零。没有。实际上,HAL + JSON和HAL + XML与HTML极为相似。这是关于REST的精彩演讲。从端点返回HTML的相关部分即将结束。youtu.be/pspy1H6A3FM就我个人而言,我使所有端点都返回json和HTML。如果你正在写发现的服务,这使得它可以很容易地浏览它...... 喘气 ......一个浏览器。
RubberDuck

4
因为提取您真正关心的数据以尝试以任何新方式使用它是一个完整的bit子?
DeadMG '17

4
通过HTTP提供HTML?这是什么?一个网站?
Ant P

50

JSON和HTML满足两个不同的语义目的。

如果要用数据填充网页,请使用JSON。如果要从部分网页构建网页,请使用HTML。

听起来好像是同一回事,但根本不是。一方面,当您使用服务器返回的HTML构建网页的一部分时,您正在服务器端工作当您将数据绑定到网页时,您是在客户端工作

另外,您必须注意HTML不能紧密地绑定到特定页面。以这种方式呈现部分页面的全部目的是使部分页面可重用,并且如果您将部分页面设置得过于具体,它将无法与其他页面组合。JSON没有这个问题,因为它只是数据,而不是网页结构。


1
“一方面,当您使用HTML构建网页的一部分时,就是在服务器端工作。” 为什么?我认为没有理由如此。显然,这对于初始页面加载是正确的,并且可以说,即使是那时也是如此,因为客户端可以请求所需的数据。
DeadMG '17

3
@DeadMG应该说“当您使用服务器返回的HTML构建网页的一部分时”(与使用服务器返回的JSON相对)
immibis

的确如此,但是既然没有什么动力可以做到这一点,我不明白这一点。
DeadMG '17

6
@DeadMG永远不会有什么动力?为服务器返回HTML?从字面上看,这就是整个SE问题所要解决的。
immibis

问题是您是否应该返回HTML。很明显,初始响应必须是HTML,但是没有其他任何API应该返回HTML的明显原因。
DeadMG '17

22

主要问题是它将服务器与客户端紧密耦合在一起,客户端必须了解HTML结构。这也使端点更加难以以新方式或新应用程序重用。

返回纯数据并让客户端呈现它可以减少耦合,并增加灵活性和可测试性-您可以在客户端上运行模拟数据的单元测试,并在服务器上运行单元测试以测试所需的数据。


11
HTML可以合理地通用。例如,您可以返回一个项目符号列表,并将其填充到div中,在该div中将受主流CSS样式化。
罗伯特·哈维

10
如果我这次需要将其塞入一个范围,那不是那么有用。或在另一个未以HTML呈现的应用程序中呈现它。
DeadMG '17

2
我将重新编写,因为它将始终构成HTML,并且HTML的形式在所有用法中必须始终保持完全一致,这不是非常有用的保证。例如,在我们的应用程序中,我们有列表,但实际上并没有使用ulli而是改为将每个列表都设为a div(不记得为什么)。如果服务器返回了一堆带有uls和lis 的HTML,那将是棘手的。
DeadMG '17

2
当您仅可以返回数据并让客户端按其认为合适的方式将其呈现为HTML时(如果什至根本无法呈现),似乎毫无意义地获得保证
DeadMG

1
我看到的唯一可以返回HTML的方案是,如果客户端没有足够的资源来自己进行渲染。
DeadMG '17

14

我想你有点后退。你说:

我们没有任何测试,因此我们没有创建此JSON端点的特殊理由

使用适当端点的原因是为了可以对其进行测试。我会说没有测试是开始编写测试的很好理由。也就是说,是否存在任何适合测试的逻辑。

200k行代码需要大量重构,并且可能很难维护。突破一些端点并对其进行测试可能是一个不错的起点。

另一个原因可能是将服务器与客户端分离。如果在不久的将来,应用程序的设计或布局发生变化,使用适当的数据格式比HTML输出要容易得多。在理想的环境中,您只需要更改客户端,而根本不需要触摸服务器。


关于布局更改的观点听起来更像是需要将模板与基础数据分离,但是没有理由这些模板必须在客户端上。确实,有很多原因使它们存在,例如,如果渲染在客户端上,则无法决定从客户端隐藏数据。如果HTML部分是通过与完整HTML页面相同的模板系统输出的,则可以重新设置皮肤的外观。
IMSoP

6

有3种方法(至少?)来构建网页:

  • 生成整个页面服务器端。
  • 从服务器返回一个裸露的页面以及代码(JavaScript),并让页面获取其数据并呈现到HTML客户端。
  • 返回部分页面加上代码,并让代码获取可放入页面的HTML预渲染块。

第一个很好。第二个也很好。这是最后一个问题。

原因很简单:现在你已经分成了HTML页面的建设纳入完全断开的部分。问题是维护之一。现在,您有两个单独的实体负责管理UI的详细信息。因此,您必须在两个单独的部分之间保持CSS和其他类似细节的同步。您更改了边栏的宽度?大。现在,返回的HTML片段会导致水平滚动,因为它对边栏宽度的假设不再成立。您更改了该块的背景颜色?太好了,现在您的HTML片段的字体颜色发生冲突,因为它假定了不同的背景色,却有人忘记测试该端点。

关键是您现在已经将知识集中在一个地方(即表示逻辑)中,这使得确定所有部分正确组合变得更加困难。通过使用JSON API,您可以将所有逻辑仅保留在前端,或者如果将数据首先呈现为HTML,则可以将其全部保留在服务器端模板中。这是关于将演示知识/逻辑保持在一个地方,因此可以对其进行统一管理并作为单个过程的一部分进行管理。HTML / CSS / JS很难保持直而不破成很多小块。

JSON API还具有使数据完全独立于表示逻辑而可用的附加好处。这允许多个不同的演示者(例如移动应用程序和网页)使用相同的数据。特别是,它可以在不使用浏览器的情况下使用数据(例如移动应用程序或夜间cron作业);这些使用者甚至可能无法解析HTML。(当然,这必然取决于情况,即不同使用者之间的数据是相同的,或者一个可以使用另一个使用者的子集。)不过,在管理演示文稿时,是否需要此功能取决于特定应用程序的要求。无论如何,逻辑都是必要的。我要说的是,如果您提前实施它,那么您将为未来的增长做好更好的准备。


2
其实,我觉得避免重复显示逻辑可以是一个很好的理由渲染HTML页面片段:如果渲染服务器上的页面的一部分(如头部和基本布局),然后基于JSON数据在客户端上其他地方,你有两组不同的模板。服务器上的部分渲染将此逻辑移回到中央表示层,该层可以使用相同的模板来呈现单个组件,就像静态组装整个页面时一样。
IMSoP

1
您是唯一提及移动广告的人,我想为此提一千个投票
Lovis

1
@IMSoP如果需要动态页面,则必须具有前端逻辑。如果仍在服务器端渲染片段,则现在必须确保前端的假设与构建片段的服务器的前提条件匹配。您无法打破这种依赖性。如果将知识分解为完全独立的系统,则很难保持同步。如果仅在前端进行渲染,则这些假设是集中的。我想我也避免在服务器端模板中将动态前端与初始状态混合使用。一个“引导程序”来启动前端更为简单。
jpmc26,2017年

4

我会说服务器返回HTML片段并将UI分配给某个元素的.innerHTML并没有错。在我看来,这是开发异步JavaScript代码的最简单方法。好处是,使用JavaScript可以完成的工作尽可能少,而在受控的后端环境中可以完成的工作则尽可能多。请记住,浏览器对JavaScript的支持各不相同,但是您的后端始终具有相同版本的后端组件,这意味着在后端中执行尽可能多的操作将意味着尽可能少的版本不兼容。

现在,有时您不仅需要HTML片段。例如,状态代码和HTML片段。然后,您可以使用具有两个成员的JSON对象,即statusCode和HTML,在检查statusCode之后,可以将第二个对象分配给某个元素的.innerHTML。因此,使用JSON和使用innerHTML绝不是替代的排他性方法。它们可以一起使用。

通过使用JSON,您甚至可以在同一响应中包含多个HTML片段,这些片段被分配给多个元素的.innerHTML。

总结:请使用.innerHTML。它使您的代码与尽可能多的浏览器版本兼容。如果需要更多,请同时使用JSON和.innerHTML。避免使用XML。


4

原则上没有错。问题是:您想实现什么?

JSON非常适合传输数据。如果您改为发送HTML,并希望客户端从HTML中提取数据,那就是垃圾。

另一方面,如果传输要呈现为HTML的HMTL,请以HTML格式发送-而不是将HTML打包为字符串,而是将字符串转换为JSON,然后传输JSON,然后将其解码,获取字符串并从字符串中提取HTML。

就在昨天,我遇到了将两个项目放入一个数组,将其转换为JSON,将JSON转换为字符串,将该字符串放入一个数组,将整个数组转换为JSON,并将其发送给客户端的代码, JSON,获取包含字符串的数组,获取字符串,从字符串中提取JSON,解码JSON,然后得到包含两个项目的数组。不要那样做


恰好+1。第一个问题是,您需要得到什么?端点以一点HTML或页脚或类似元素的形式返回边栏广告几乎没有什么错误。
SQB

3

这一切都取决于API的目的,但是通常您所描述的是对关注点分离的强烈违反:

在现代应用程序中,API代码应负责数据,而客户端代码应负责表示。

当API返回HTML时,您就将数据和表示紧密地结合在一起。当API返回HTML时,您唯一(可以轻松地)对该HTML执行的操作就是将其显示为较大页面的一部分。从不同的角度来看,API唯一适合做的就是为您的页面提供HTML。另外,您已经在客户端和服务器代码中分布了HTML。这会使维护变得头疼。

如果您的API返回JSON或其他某种形式的纯数据,它将变得更加有用。现有的应用仍可以使用该数据,并适当地呈现它。不过,现在,其他事物可以使用API​​来访问相同的数据。同样,维护也更容易-所有HTML都位于一个位置,因此,如果您要重新设计整个网站的样式,则无需更改API。


5
“在现代应用程序中,API代码应负责数据,而客户端代码应负责表示。” 为什么总是这样?我同意这是一种常见的模式,并使某些事情变得容易,但是我认为没有理由将其提升到“应该”的水平……这是一个决定,需要视具体情况而定,在某些情况下,您可能需要做出不同的决定,这当然是有原因的。
Jules

@Jules,因为如果您拥有API和客户端,则同时负责渲染将违反关注点分离。(现在,您不必一定有一个API和一个客户端。您只能有一个组件,并且可以完成整个演示文稿。但是然后您就没有API)
njzk2

@ njzk2仅仅因为API提供了HTML数据并不意味着它已经呈现了它。例如,可能会将HTML视为blob并将其存储在数据库中。另外,可能需要在服务器而不是客户端上进行某些渲染(例如,为搜索引擎提供静态页面),因此重用该功能可以看作是消除了重复。
Jules

1
此外,完全有可能生成一个客户端和api对,其中所有呈现均在服务器上进行,并且客户端仅将传递的HTML插入其DOM中的预定义插槽中。jQuery具有专用于此类客户端的整个模块,对我来说,它们必须是相当普遍的。
Jules

1
@Jules很多事情是合理的,这不是它们合理的原因。
njzk2

2

HTML与特定的设计和使用联系在一起。

使用HTML,如果要更改页面布局,则需要更改服务器调用生成html的方式。通常,这需要后端程序员。现在您有了后端程序员,根据定义,他们不是最好的html编写者,他们正在处理这些更新。

使用JSON,如果页面布局发生更改,则现有的JSON服务器调用不必完全更改。相反,您的前端开发人员甚至设计人员会更新模板,以根据相同的基本数据生成所需的不同HTML。

此外,JSON可以成为其他服务的基础。您可能具有不同的角色,需要以不同的方式查看相同的基本数据。例如,您可能有一个客户网站,该网站在订单页面上显示有关产品的数据,而销售代表的内部销售页面则以非常不同的布局显示相同的数据,也许还有一些普通客户无法获得的其他信息。使用JSON,可以在两个视图中使用相同的服务器调用。

最后,JSON可以更好地扩展。近年来,我们在客户端JavaScript框架方面有些过分。我认为是时候真正退后一步,开始思考我们正在使用什么javascript,以及它如何影响浏览器性能……尤其是在移动设备上。也就是说,如果您运行的站点足够大,需要服务器场或群集,而不是单个服务器,则JSON可以更好地扩展。用户将免费为您提供在浏览器中的处理时间,如果您可以利用它,可以减少大型部署中的服务器负载。JSON也使用较少的带宽,因此,如果足够大的话并适当地使用它,JSON便宜得多。当然,如果最终提供40KB的库以将2KB的数据解析为7KB的html,它的伸缩性也可能会变差,所以再次重申:知道自己在做什么是值得的。但是JSON有潜力提高性能和成本。


1

如果端点满足其要求,则没有任何问题。如果需要吐出已知消费者可以有效解析的html,那么为什么不呢?

问题在于,在一般情况下,您希望端点吐出格式正确且可被标准解析器有效解析的有效负载。所谓有效解析,是指声明式解析。

如果您的客户端被迫读取有效负载并使用循环和if语句从中撬开开放信息位,则它是无法有效解析的。HTML本身就是一种宽恕,因为它不需要自身格式正确。

现在,如果您确定自己的html兼容xml,那么您就是金牌了。

话虽如此,我对此有一个重大问题:

我要告诉你的是:返回HTML的端点减少了您对JavaScript库的依赖,并减轻了用户浏览器的负担,因为它不需要解释/执行JS代码来创建DOM对象-HTML已经存在,只需解析元素并渲染它们即可。当然,这意味着我们在谈论合理数量的数据。10 MB的HTML数据是不合理的。

无论如何削减,这都是一个坏主意。数十年的集体工业经验向我们表明,总的来说,从显示(或视图)中分离数据(或模型)是一个好主意。

在这里,您将两者混为一谈,以快速执行JS代码。那是一个微优化。

除了非常琐碎的系统外,我从来没有将此视为一个好主意。

我的建议?不要这样 HC SVNT DRACONES,YMMV等


0

JSON只是结构化数据的文本表示形式。客户端自然需要一个解析器来处理数据,但是实际上所有语言都具有JSON解析器功能。使用JSON解析器比使用HTML解析器要有效得多。占用空间小。HTML解析器不是这样。

在PHP中,您只需要使用json_encode($data)它,而解析则取决于另一端的客户端。而且,当您从Web服务中获取JSON数据时,您只需使用$data=json_decode($response)即可决定如何像使用变量一样使用数据。

假设您为移动设备开发了一个应用程序,为什么在移动应用程序很少使用Web浏览器解析数据时为什么需要HTML格式?许多移动应用程序使用JSON(最常见的格式)来交换数据。

考虑到移动设备通常是按计划计费的,为什么您要使用比JSON占用更多带宽的HTML?

当HTML的词汇量受到限制并且JSON可以定义数据时,为什么使用HMTL?{"person_name":"Jeff Doe"}比HTML提供更多有关数据的信息,因为它仅定义HTML解析器的结构,而不定义数据。

JSON与HTTP无关。您可以将JSON放入文件中。您可以将其用于配置。Composer使用JSON。您也可以使用它将简单变量保存到文件中。


0

很难将是非归类。IMO,我要问的问题是:“ 应该 ”还是“ 可以用更少的钱做? ”。

每个端点都应努力以尽可能少的内容进行通信。信噪比通常为HTTP代码<JSON <XHTML。在大多数情况下,最好选择噪声最小的协议。

我对@machado加载客户端浏览器的观点有所不同,因为对于现代浏览器而言,这不是问题。它们中的大多数都可以很好地处理HTTP代码和JSON响应。而且,尽管您目前没有测试,但长期维护一个噪音较小的协议会比上面的协议便宜。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.