У нас есть веб-приложение, в котором бэкэнд — это Spring Boot, а интерфейс — это реакция. Мы пытаемся интегрировать эти приложения таким образом, чтобы мы могли использовать файл jar загрузки spring для запуска их обоих на одном и том же порту.
Следующий фрагмент кода Java используется для интеграции.
@Bean
public RouterFunction<ServerResponse> htmlRouter(@Value("classpath:/static/index.html") Resource html) {
return RouterFunctions.route(
GET("/*"),
request -> ServerResponse.ok().contentType(MediaType.TEXT_HTML).bodyValue(html)
);
}
Это отлично работает, когда мы создаем сборку внешнего интерфейса с использованием сборки реактивных скриптов. Мы хотим использовать сборку веб-пакета, поскольку таких приложений будет несколько, и они будут интегрированы с использованием микроинтерфейса, который будет работать только при наличии веб-пакета. При попытке сделать это создается файл jar. Когда мы запускаем этот файл jar и нажимаем на URL-адрес, мы получаем следующую ошибку:
refused to execute script from 'http://localhost:8765/abc/xyz' because its MIME type ('text/html') is not executable, and strict MIME type checking is enabled.
Часть конфигурации веб-пакета
output: {
path: path.join(__dirname, 'build'),
publicPath: '/',
filename: 'bundle.js',
}
Ниже приведена структура папок проекта.
Ваш маршрутизатор настроен на обработку всех URL-адресов и возврат HTML-страницы:
return RouterFunctions.route(
GET("/*"),
request -> ServerResponse.ok().contentType(MediaType.TEXT_HTML).bodyValue(html)
);
Если ваша страница содержит тег <script src = "...">
, браузер получит URL-адрес, чтобы получить скрипт.
Сервер вернет HTML-страницу с типом содержимого text/html
, что вызовет сообщение об ошибке.
потому что вместо этого браузер ожидает text/javascript
.
Вы можете попробовать использовать представления скриптов Spring для этой цели: если вы думаете об этом, в конце концов вам понадобится какой-то движок для работы с SSR. Для React документация предлагает использовать Nashorn.
В документации предлагается возможная конфигурация для разных библиотек сценариев:
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureViewResolvers(ViewResolverRegistry registry) {
registry.scriptTemplate();
}
@Bean
public ScriptTemplateConfigurer configurer() {
ScriptTemplateConfigurer configurer = new ScriptTemplateConfigurer();
configurer.setEngineName("nashorn");
configurer.setScripts("mustache.js");
configurer.setRenderObject("Mustache");
configurer.setRenderFunction("render");
return configurer;
}
}
В конкретном случае использования React мы можем найти другие, более полные примеры, например, в этом репозитории Github:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewResolverRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.script.ScriptTemplateConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureViewResolvers(ViewResolverRegistry viewResolverRegistry) {
viewResolverRegistry.scriptTemplate().prefix("/templates/").suffix(".html");
}
@Bean
public ScriptTemplateConfigurer scriptTemplateConfigurer() {
ScriptTemplateConfigurer scriptTemplateConfigurer = new ScriptTemplateConfigurer("nashorn");
scriptTemplateConfigurer.setScripts("/js/polyfill.js", "/js/built/bundle-server.js");
scriptTemplateConfigurer.setRenderFunction("render");
scriptTemplateConfigurer.setSharedEngine(false);
return scriptTemplateConfigurer;
}
}
Или вот этот, устаревший, но, думаю, тоже полезный:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.view.script.ScriptTemplateConfigurer;
import org.springframework.web.servlet.view.script.ScriptTemplateViewResolver;
/**
* @author David Hancock
*/
@Configuration
public class SSRConfiguration {
@Bean
public ViewResolver reactViewResolver() {
return new ScriptTemplateViewResolver("/public/", ".html");
}
@Bean
public ScriptTemplateConfigurer reactConfigurer() {
ScriptTemplateConfigurer configurer = new ScriptTemplateConfigurer();
configurer.setEngineName("nashorn");
configurer.setScripts(
"public/nashorn-polyfill.js",
"public/server.js"
);
configurer.setRenderFunction("render");
configurer.setSharedEngine(false);
return configurer;
}
}
Как видите, в реализации они выглядят довольно похоже: в основном нужно указать скрипты, которые должны быть загружены скриптовым движком, один конечно bundle
сгенерированный webpack
, и как минимум еще один (см. это или это другой пример), полифилл для поддержки window
и т. д.
Я наткнулся на еще один хороший пример: он для Vue, а не для React, но даже в этом случае он дает хороший пример использования движка Nashorn для SSR.
В продолжение комментария, предоставленного @walen, вероятно, гораздо лучшим решением, чем использование Spring Boot и какого-либо типа механизма сценариев, реализованного на Java (в настоящее время устаревшего), для обслуживания содержимого React, является архитектура вашего приложения по-другому, независимое развертывание вашего бэкэнда и внешнего интерфейса. Затем используйте NodeJS
фактически запустите свое приложение React и, возможно, nginx, Apache или другой тип обратного прокси-сервера для обслуживания всего, это обычный способ продолжить. Вы можете использовать Docker (Kubernetes и т. д.) или аналогичную контейнерную инфраструктуру другого типа для развертывания решения в целом. С точки зрения микросервисов эта другая архитектура предпочтительнее.
Nashorn устарел в Java 11 (2018 г.) и окончательно удален в Java 15 (2020 г.).
Большое спасибо за отзыв @walen, я ценю это. Да, я знал об этом, но OP не упоминает версию JDK, которую он использует, и, как вы можете прочитать в ответе, текущая документация Spring в настоящее время все еще упоминает ее как подходящий механизм Javascript для этой цели: Я думаю, что GraalVM не подходит, по крайней мере, в этом контексте.
@walen Получается, что GraalVM на самом деле можно использовать и для этой цели, правда, не в другом контексте React , а чуть более проработанным образом 1 2.
Спасибо, но я пробовал такие вещи, ничего не получалось