使用Java和ReactJS进行服务器端渲染的微服务UI前端

6
我的当前设计是让客户端使用浏览器连接到我的(Java)Web API网关,Web API网关将调用每个(Java)微服务来获取它们的JSON数据并将其返回给在客户端上发出请求的UI组件。
仅有的客户端渲染将来自于每个ReactJS UI组件对网关进行重复请求。
在服务器端,完整的HTML视图将在发送回客户端之前呈现。
Client browser

     ▼ (Request Dashboard View)

Web API Gateway

     ▼ (Request microservice JSON data)

Microservice A JSON Data
Microservice B JSON Data
Microservice C JSON Data
Microservice D JSON Data

     ▼ (Return JSON Data to gateway)

Web API Gateway

     ▼ (Render HTML and return to Client)

Client browser

     ▼ (ReactJS UI Components request data from API Gateway)

这里有些不清楚,最好让每个UI组件与Web API网关或其来自的父微服务通信以获取数据?
考虑因素:
- 使UI组件与Web API网关通信似乎是合理的,但会将微服务耦合到网关上,这意味着要在微服务上公开新API,网关也需要更新。 - 让UI组件直接与其微服务通信以获取数据可以消除更新Web API网关的需要,从而使它们之间的耦合更少。但这会将微服务暴露给客户端浏览器的外部调用。
设计决策:
- 在API网关中放置UI组件创建了一个UI单体,而不是让每个微服务负责自己的UI组件。使用单体方法简化了解决方案,并避免了在客户端请求特定视图时必须聚合每个微服务UI组件的复杂性。
工具:
- Java - Nashorn - Dropwizard - ReactJS - Gradle - Webpack - NodeJS - NPM
我应该如何使用Java和ReactJS在Web API网关上聚合多个微服务UI组件,然后将这些预渲染的HTML数据与JavaScript应用程序一起提供给客户端?
有用的参考资料: - 使用Java 8和Nashhorn进行服务器端渲染 http://winterbe.com/posts/2015/02/16/isomorphic-react-webapps-on-the-jvm/

你从每个微服务中以json格式加载数据 - Constantin Galbenu
@ConstantinGALBENU 是的,但我正在寻求有关如何执行该过程的指导。我已更新问题。 - David
我仍然不明白你是否需要服务器端渲染。 - Constantin Galbenu
React 组件将在微服务上使用 JavaScript 编写,JavaScript 可以返回到网关,然后与其他组件聚合形成完整的视图。无需将 React 组件作为 JSON 返回到网关。或者我错了吗?在网关可能需要服务器端渲染。 - David
让我们在聊天室里继续这个讨论 - David
显示剩余4条评论
2个回答

3
所以,一个 React 组件需要两个东西:JavaScript 源代码和数据。
JavaScript 源代码可以由 CDN 提供。
数据必须由微服务提供。
如果你不想进行服务器端渲染,则骨架 index.html 文件以及 JS 文件可以由 CDN 提供。
如果您需要服务器端渲染(例如用于 SEO),则 API 网关(或另一个 Web 服务器)将使用 NodeJS 请求组件的源代码和来自微服务的数据来呈现组件并将完整的 HTML 返回给浏览器。
在客户端上,React 将继续使用 API 网关从正确的微服务加载其他数据作为 JSON。

这是非常有用的信息,帮了我很多忙,但我正在使用Java而不是NodeJS,并且我相信ReactJS UI组件应该仅访问Web API网关,而不是它来自的微服务。 - David
无论您使用Java还是NodeJS来构建微服务都没有关系。您可以使用任何技术栈,组件也不会在意。重点是组件只从微服务中下载JSON数据,使用API Gateway或不使用都可以。只有在需要服务器端渲染时才使用NodeJS - Constantin Galbenu
我知道微服务的实现方式并不重要,但我正在使用Java/Dropwizard。我的问题是关于使用Java/ReactJS堆栈进行服务器端渲染的。 - David
你的情况比较复杂,因为你将组件的源代码保留在微服务中。你应该将它们全部保存在一个位置,即安装了 NodeJS 的 Web 服务器上,并从该 Web 服务器呈现它们作为“单页应用程序”。 - Constantin Galbenu
你应该只使用Java来生成JSON动态内容。 - Constantin Galbenu
显示剩余4条评论

3

问题

如何在Web API网关上进行ReactJS UI组件的服务器端渲染聚合。

解决方案

使用类似Mustache这样的模板框架,在服务器端注入每个ReactJS组件的渲染HTML输出,然后将此HTML返回给客户端。

Github存储库https://github.com/damorton/dropwizardheroku-webgateway

服务器端

我在Web API网关上实现的解决方案首先从微服务请求JSON数据,然后在注入来自微服务的JSON数据作为Props的同时呈现ReactJS组件。一旦我获得了完全呈现的带有数据的ReactJS组件作为HTML字符串,我就使用Mustache模板将完全呈现的ReactJS组件HTML注入到Mustache模板中,然后将其返回给客户端。

WebGatewayResource.java

@GET
@Produces(MediaType.TEXT_HTML)
public IndexView index() throws IOException {

    // Get events json data from Events microservice
    ApiResponse events = getEventsJsonData();

    // Render the Events component and pass in props
    @SuppressWarnings("unchecked")
    List<Object> eventsProps = (List<Object>) events.getList();
    String eventsComponent = this.nashornController.renderReactJsComponent(kEventsUiComponentRenderServerFunction, eventsProps);

    IndexView index = new IndexView(eventsComponent);
    return index;
}

注意:Dropwizard 在 Mustache 模板方面执行了很多魔法,所以只需要创建一个 index.mustache 文件,并在构建 IndexView 类时引用它。将此 View 返回给客户端告诉 Dropwizard 渲染视图并返回 HTML。

index.mustache

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Dropwizard Heroku Event Service</title>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/react/15.5.4/react.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/react/15.5.4/react-dom.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/react/15.5.4/react-dom-server.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.24.0/babel.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.16.1/axios.min.js"></script>
</head>
<body>
  <h1>Events</h1>
  <div id="events">{{{eventsComponent}}}</div>
  <script type="text/javascript" src="assets/js/bundle.js"></script>
  <script type="text/javascript" src="assets/js/client.js"></script>
</body>
</html>

客户端

在客户端上,为了解决ReactJS组件的props在组件初始挂载时不可用导致客户端和服务器端渲染的HTML不同的问题,页面加载时会调用一个JavaScript函数从网关请求JSON数据。

client.js

var loadEventsFromServer = function(eventsUrl) {
    axios.get(eventsUrl).then(function(res) {
        var data = res.data.list;       
        renderClientEvents(data);
    });
};

loadEventsFromServer('https://domain.webapigateway.com/events');

ReactJS

当组件被挂载时,客户端的HTML不会重新渲染。React知道从服务器端呈现已经存在的HTML,并且在组件挂载时只添加每个组件的事件监听器。这使得React能够单独更新其组件,并利用服务器端呈现的优势。


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