带有 Java 和 ReactJS 服务器端渲染的微服务 UI 前端

IT技术 java reactjs microservices server-side-rendering
2021-05-21 19:41:52

我目前的设计是让客户端使用浏览器连接到我的(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
  • 纳斯洪
  • 下拉向导
  • ReactJS
  • 摇篮
  • 网络包
  • 节点
  • 新产品管理

如何使用 Java 和 ReactJS 在 Web API 网关上聚合多个微服务 ui 组件,然后将此预渲染的 HTML 数据与 JavaScript 应用程序一起提供给客户端?

有用的参考资料:

2个回答

因此,aReact component需要两件事:JavaScript源代码和数据。

JavaScript 源代码可以由 CDN 提供。

数据必须由微服务提供。

如果您不希望服务器端呈现,那么框架 index.html 文件以及JS文件由 CDN 提供。

如果您需要服务器端渲染(例如出于 SEO 目的),那么 API 网关(或其他 Web 服务器)将NodeJS通过从 CDN 请求源代码和从微服务请求数据来渲染组件,然后将完整的返回HTML给浏览器.

在客户端,React将继续从正确的微服务加载其他数据,就像JSON使用API gateway.

问题

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

解决方案

使用像Mustache这样的模板框架来注入每个 ReactJS 组件服务器端呈现的 HTML 输出,然后将此 HTML 返回给客户端。

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

服务器端

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

网关资源.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来自网关的数据。

客户端.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 单独更新其组件,并利用服务器端渲染。