javascript 使用React和Sping Boot Java的SSR问题

axr492tv  于 2023-05-16  发布在  Java
关注(0)|答案(2)|浏览(253)

bounty还有3天到期。回答此问题可获得+500声望奖励。Ashh正在寻找典型答案

我们有一个Web应用程序,其中后端是Sping Boot ,前端是React。我们试图以这样一种方式集成这些应用程序,即我们可以使用Sping Boot jar文件在同一端口上运行它们。
下面的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)
        );
    }

当我们使用react-scripts build创建前端构建时,这工作得很好。我们希望利用webpack构建,因为将有多个这样的应用程序,它们将使用微前端集成,只有当webpack到位时才能工作。当尝试这样做时,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.

Webpack配置的一部分

output: {
        path: path.join(__dirname, 'build'),
        publicPath: '/',
        filename: 'bundle.js',
    }

以下是项目的文件夹结构

ndasle7k

ndasle7k1#

您的路由器配置为处理所有URL并返回HTML页面:

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

如果您的页面包含<script src="...">标记,浏览器将获取URL以获取脚本。服务器将返回一个内容类型为text/html的HTML页面,这会触发错误消息,因为浏览器需要的是text/javascript

xmakbtuz

xmakbtuz2#

您可以尝试使用Spring的script views来实现此目的:如果你考虑到这一点,最终你需要某种类型的引擎来处理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的具体用例中,我们可以找到不同的、更完整的示例,例如this Github repository

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;
  }

}

或者this other one,过时了,但我认为仍然有用:

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;
    }

}

正如你所看到的,它们在实现中看起来非常相似:基本上,您需要指出脚本引擎应该加载的脚本,当然是由webpack生成的bundle,至少还有一个(参见thisthis other example),用于支持window的polyfill等。
我遇到了another good example:它是针对Vue的,而不是针对React的,但即使在这种情况下,它也提供了一个使用Nashorn引擎进行SSR的好例子。
作为@walen提供的评论的后续,可能比使用Sping Boot 和Java实现的某种类型的脚本引擎(现在已被弃用)更好的解决方案来服务React内容,是以不同的方式构建您的应用程序,独立部署您的后端和前端。然后,使用NodeJS实际运行您的React应用程序,并可选地使用nginx,Apache或其他类型的反向代理来服务所有内容,这是正常的方法。您可以使用Docker(Kubernetes等)或某种类型的等效容器基础设施来整体部署解决方案。从微服务的Angular 来看,这种不同的架构更可取。

相关问题