微服务 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 网关或它来自的父微服务通信以获取数据吗?
注意事项
- 让 UI 组件与 Web API 网关通信似乎很合理,但会将微服务耦合到网关,这意味着在微服务上公开一个新的 API 网关将也需要更新。
- 让 UI 组件直接与其微服务对话以获取数据,这样就无需同时更新 Web API 网关,从而降低它们的耦合度。但这随后会将微服务暴露给来自客户端浏览器的外部调用。
设计决策
- 在 API 网关中拥有 UI 组件创建了一个 UI 整体,而不是让每个微服务负责其自己的 UI 组件。使用整体方法简化了解决方案,还避免了在客户端请求特定视图时必须聚合每个微服务 UI 组件的复杂性。
工具:
- Java
- 纳肖恩
- Dropwizard
- ReactJS
- Gradle
- Webpack
- NodeJS
- NPM
如何使用 Java 和 ReactJS 在 Web API 网关上聚合多个微服务 ui 组件,然后提供此预渲染 HTML数据连同 Java脚本应用到客户端?
有用的参考资料:
- 使用 Java 8 和 Nashhorn http://winterbe.com/posts/2015/02/16/isomorphic-react-webapps-on-the-jvm/
的服务器端渲染
因此,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 单独更新其组件,并利用服务器端渲染。
我目前的设计是让客户端使用浏览器连接到我的 (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 网关或它来自的父微服务通信以获取数据吗?
注意事项
- 让 UI 组件与 Web API 网关通信似乎很合理,但会将微服务耦合到网关,这意味着在微服务上公开一个新的 API 网关将也需要更新。
- 让 UI 组件直接与其微服务对话以获取数据,这样就无需同时更新 Web API 网关,从而降低它们的耦合度。但这随后会将微服务暴露给来自客户端浏览器的外部调用。
设计决策
- 在 API 网关中拥有 UI 组件创建了一个 UI 整体,而不是让每个微服务负责其自己的 UI 组件。使用整体方法简化了解决方案,还避免了在客户端请求特定视图时必须聚合每个微服务 UI 组件的复杂性。
工具:
- Java
- 纳肖恩
- Dropwizard
- ReactJS
- Gradle
- Webpack
- NodeJS
- NPM
如何使用 Java 和 ReactJS 在 Web API 网关上聚合多个微服务 ui 组件,然后提供此预渲染 HTML数据连同 Java脚本应用到客户端?
有用的参考资料:
- 使用 Java 8 和 Nashhorn http://winterbe.com/posts/2015/02/16/isomorphic-react-webapps-on-the-jvm/ 的服务器端渲染
因此,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 单独更新其组件,并利用服务器端渲染。