Node.js和单页Web应用程序

12

我正在研究使用express.js作为后端,JS作为客户端。我的应用是一个单页面Web应用。

服务器只会提供JSON消息,我的问题是关于express的“路由”。 是不是应该使用路由来连接UI和服务器端的业务逻辑? 在我的单页应用中,这将如何工作?

比如说,客户端向服务器发起Ajax调用,查找数据库中的某个值,然后有服务器脚本将JSON返回给UI。那么UI和节点脚本之间的关系如何设置?

有人能解释一下吗?


尽管您可能向客户端提供单个页面,但应用程序路由器将不得不处理许多其他资源,包括外部CSS、JS文件、图像、音频/视频文件、模板以及当然还有您的REST或自定义RPC端点,您的单页应用程序将调用这些端点来获取数据。 - cbayram
不太熟悉Express,但可以看看这个问题:https://dev59.com/HWcs5IYBdhLWcg3woFft - cbayram
为了让客户端代码获得一个JSON,例如获取书籍列表,即使应用程序是单页的,我仍然会路由/ books吗? - reza
@reza 也许你需要更明确地阐述你的问题。你困惑于路由方面的哪些具体问题? - Alex Wayne
2个回答

42
单页应用程序是指存在于单个HTML文档中的应用程序。这意味着,如果您想根据应用程序的状态向用户显示一些不同的内容,就需要进行DOM操作(删除并替换当前文档中某些元素以显示不同的HTML),以更新用户看到的“视图”。如果这对您来说很明显,请不要介意,我认为我应该从这里开始。跟着我,我将解释您的路由情况将如何发挥作用(或多或少)。
URL由几个不同的部分组成,每个部分都会向浏览器提供特定的信息,以下载用户试图访问的资源所需的信息。通常,您要寻找的资源在某个服务器上,浏览器知道这一点是因为URL中包括“协议”(“http:”)和“主机”(“www.mydomain.com”)等部分,因此它会前往该服务器以查找您正在请求的内容。 URL中还有“查询”参数,这些参数为服务器提供了有关特定操作的其他信息,例如搜索查询的搜索词。在查询参数之后,是“哈希”。哈希是单页应用程序的神奇之处……呃,或者说,算是吧……
先来讲一下哈希。当您向URL添加“#”时,浏览器会将其后面的信息解释为当前显示的文档中的某个位置(元素)。这意味着,如果您有一个具有“id”为“main”的元素,并且将“#main”添加到URL的末尾,例如:“http://www.example.com#main”,浏览器将“滚动”(通常是“跳转”)到该元素的开头,以便您可以看到它。但请注意,如果您输入'http://www.example.com/#main' (哈希符号与URL之间用斜杠分隔),那么您将强制进行完整的页面重新加载,并且浏览器将试图在服务器上找到名为“#main”的文件(我敢打赌它找不到)。
这里要记住的是,如果URL中存在哈希,则浏览器不会尝试从当前文档导航离开,特殊情况已经提到了,对于单页应用程序来说,这非常好,因为它们不想从页面导航离开或从服务器请求新文档。(看看单页应用程序的路由方式有什么不同?)
现在,关于哈希的整个问题并不是单页应用程序必须处理的事情,因为您可以创建一个而不处理它。实际上,一堆点击处理程序和DOM操作就足够了。但是,这意味着用户将无法共享应用程序中特定视图的链接。URL永远不会改变,我们永远无法直接导航到任何特定的视图。我们总是从您的应用程序的起始位置开始,这可能很容易成为令人讨厌的情况。如果你的单页面应用程序将有不同的视图,并且希望用户可以通过书签或链接直接导航到特定的视图,则需要在前端实现一种路由方式,除了必须在后端实现的路由(数据API等),这意味着你需要利用hash。我不想讨论不同框架如何在前端实现路由,但基本上是在用户点击链接时更新浏览器地址栏,监视地址栏以确定当前URL并将与该URL相关联的HTML加载到文档树中指定的位置的浏览器地址栏的一件事。
因此,在单页应用程序中,你在服务器上只有一个路由来处理渲染应用程序HTML文档(index.html),而你还有负责处理应用程序数据的路由(在数据库中创建新实例、登录和注销、编辑或破坏数据库中的实例以及获取数据等),这些路由通过AJAX请求调用。
这实际上是相当复杂的情况,因为HTML5允许我们放弃hash(通过服务器上的一些链接重写)并且能够使用“后退”和“前进”按钮,就好像我们已经导航离开了原始文档一样(但我们没有,因为我们只是将浏览器指向完全相同的URL,只是具有修改的hash值,因此没有发生新页面加载)。通过利用浏览器的History API可以实现传统的网站导航和链接,该API从IE版本10开始提供(我认为),其它主要的浏览器供应商早在很长时间前就已经掌握了这个技术,因此利用这项技术的框架将允许您的用户在URL中不使用hash导航到您的应用程序。解释这一点是一个转移和理解单页应用程序中的路由并不必要,但它很有趣,你最终还是需要学习它的。
应该使用AJAX从服务器请求JSON。AJAX请求将总是命中你的服务器,因为你不会在AJAX请求中包含hash符号(这样做是荒谬的,因为hash仅用于文档内浏览),因此服务器端的路由必须负责公开您的数据API(考虑RESTful)。尽管这不是单页应用程序中它们唯一的目的,但也许是它们最重要的目的。
所以,总之,你将有两组路由。一个在客户端(作为像AngularJS或EmberJS这样的客户端框架的一部分,列表还在继续……我更喜欢Angular,但对于那一个存在相当陡峭的学习曲线),另一个在服务器上。当你考虑“服务器路由”时,请考虑数据API。当你考虑“页面路由”时,请记住所有这些都在客户端上处理,通过你最初的服务器响应提供的JavaScript(这是与渲染HTML到浏览器有关的唯一必要的服务器端路由,加载你的“index.html”和所有必要的脚本和样式表等)。你将使用express.static中间件来提供静态文件,因此不必担心为那些东西分配路由。

编辑:快速提到AJAX实现。在服务器端,您将拥有与Alex提供的示例类似的路由,并使用您选择的框架或库公开的任何XMLHttpRequest(XHR)对象从客户端调用这些URL。现在认为将这些请求实现为Promises是标准且最佳实践http://wiki.commonjs.org/wiki/Promises/A。您应该自己阅读一些相关内容,但我可以简要概括一下,它是一种异步操作,类比于同步操作中的“try、catch、throw”。您将实例化一个Promise对象,并通过它尝试从服务器加载数据,例如,通过GET请求。确保您已经分配了函数来处理发送到您所请求的URL(服务器端路由)的请求!您通过此对象进行服务器请求时,该对象承诺会在请求结果从服务器返回后向您返回结果(无论请求成功或失败)。如果成功,它将调用您编写的一个函数并提供来自服务器的数据。如果失败,它将调用另一个由您编写的函数,并向其提供错误对象(或故障原因),以便您可以适当地处理错误。

希望这有助于回答您的问题。


哇,非常感谢您!您花了那么多时间来解释得如此清楚。谢谢,这确实有所帮助。顺便说一下,就在昨天,我正在观看一个关于 Promise/A+ 的精彩演讲。非常有用的链接:http://www.youtube.com/watch?v=hf1T_AONQJU - reza
很好,我很高兴它能够帮到你。这是我第一次实际为SO做出贡献,考虑到我经常在这里寻找答案,可能有点混乱...你使用什么框架来构建前端? - ryan.l

1
你只需要路由动态服务的请求。你的HTML、CSS、JS都是静态资源。所以你只需要处理数据的路由。
听起来你想要一个Restful API,基本上意味着你有特定资源的URL和HTTP动词来操作它们。
例如:
- `GET /books.json` - 获取所有书籍 - `POST /books.json` - 在请求体中传递属性创建新书籍 - `GET /books/123.json` - 获取ID为123的书籍 - `PUT /books/123.json` - 在请求体中传递属性更新现有书籍 这篇博客文章似乎展示了如何在Express中设置它。 一旦你拥有一个合理的提供JSON的API,你只需要根据你想获取的对象,使你的AJAX调用使用它。

这是单页应用程序的常见做法吗?使用路由来处理数据和HTML页面吗? - reza
不,我的意思是你只需要为数据设置路由。你的应用程序只是静态资源。你的服务器需要处理的是数据。 - Alex Wayne
1
一个来自客户端到服务器的Ajax调用可能会有所帮助。客户端调用一个接受一个参数(可能是bookId)的节点函数。 - reza

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接