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

Microservices UI Frontend with Java and ReactJS Server Side Rendering

我目前的设计是让客户端使用浏览器连接到我的 (Java) Web API 网关,Web API 网关将调用每个 (Java ) 微服务​​来获取他们的 JSON 数据,并将其 return 发送到在客户端发出请求的 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 网关或它来自的父微服务通信以获取数据吗?

注意事项

设计决策

工具:

如何使用 Java 和 ReactJS 在 Web API 网关上聚合多个微服务 ui 组件,然后提供此预渲染 HTML数据连同 Java脚本应用到客户端?

有用的参考资料:

因此,React component 需要两样东西:JavaScript 源代码和数据。

JavaScript源代码可以通过CDN提供。

数据必须由微服务提供。

如果您不想在服务器端呈现,则框架 index.html 文件连同 JS 文件由 CDN 提供。

如果您需要服务器端呈现(例如出于 SEO 目的),那么 API 网关(或另一个 Web 服务器)将通过从 NodeJS 请求它们的源代码来呈现组件CDN 及其来自微服务的数据然后 return 完整 HTML 到浏览器。

在客户端,React 将继续使用 API gateway.

从正确的微服务加载其他数据作为 JSON

问题

如何在 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 模板中,然后 returned 到客户端.

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 class。将这个 View 返回给客户端告诉 Dropwizard 渲染视图和 return 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>

客户端

在客户端,为了解决客户端和服务器端渲染 HTML 不同的问题,因为 ReactJS 组件的 props 在最初安装组件时不可用,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 单独更新其组件,并利用服务器端渲染。