Проблема с SSR с загрузкой React и Spring Java

У нас есть веб-приложение, в котором бэкэнд — это 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',
    }

Ниже приведена структура папок проекта.

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
0
243
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ваш маршрутизатор настроен на обработку всех URL-адресов и возврат HTML-страницы:

return RouterFunctions.route(
    GET("/*"),
    request -> ServerResponse.ok().contentType(MediaType.TEXT_HTML).bodyValue(html)
);

Если ваша страница содержит тег <script src = "...">, браузер получит URL-адрес, чтобы получить скрипт. Сервер вернет HTML-страницу с типом содержимого text/html, что вызовет сообщение об ошибке. потому что вместо этого браузер ожидает text/javascript.

Спасибо, но я пробовал такие вещи, ничего не получалось

Ashh 12.05.2023 17:29
Ответ принят как подходящий

Вы можете попробовать использовать представления скриптов 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 15.05.2023 10:33

Большое спасибо за отзыв @walen, я ценю это. Да, я знал об этом, но OP не упоминает версию JDK, которую он использует, и, как вы можете прочитать в ответе, текущая документация Spring в настоящее время все еще упоминает ее как подходящий механизм Javascript для этой цели: Я думаю, что GraalVM не подходит, по крайней мере, в этом контексте.

jccampanero 15.05.2023 16:18

@walen Получается, что GraalVM на самом деле можно использовать и для этой цели, правда, не в другом контексте React , а чуть более проработанным образом 1 2.

jccampanero 15.05.2023 17:28

Другие вопросы по теме