使用Dropwizard服务多个静态资产



我有一个react应用程序,我正在构建它,并试图使用AssetBundle提供服务,例如:

    @Override
    public void initialize(final Bootstrap<PersonalWebsiteConfiguration> bootstrap) {
        bootstrap.addBundle(new SwaggerBundle<PersonalWebsiteConfiguration>() {
            protected SwaggerBundleConfiguration getSwaggerBundleConfiguration(final PersonalWebsiteConfiguration configuration) {
                return configuration.swaggerBundleConfiguration;
            }
        });
        bootstrap.addBundle(new AssetsBundle("/build", "/", "index.html"));
    }

我还添加了配置

server:
  rootPath: /api

这样就不会与我的API发生冲突。

这只适用于我的React应用程序的登录页。每当我尝试路由/登录/仪表板时,都找不到UI中的此页面。所以我尝试添加更多的捆绑包来解决路由问题:

        bootstrap.addBundle(new AssetsBundle("/build", "/", "index.html"));
        bootstrap.addBundle(new AssetsBundle("/build", "/login", "index.html"));
        bootstrap.addBundle(new AssetsBundle("/build", "/dashboard", "index.html"));

现在,只有仪表板在工作。有人知道如何为具有多个路由/页面的React构建提供服务吗。

对于单页应用程序,您需要每个客户端路由返回index.html(以支持浏览器重新加载或在/以外的路径上登录(据我所知,Dropwizard AssetBundle无法做到这一点,即用index.html为所有路由提供服务。参见类似(旧(问题。

您可以自己实现servlet过滤器,也可以使用类似这样的社区插件。

我必须说,另一种方法对我更有效,根本不使用dropwizard来服务静态资产,只将其用作后端API。使用CDN路由或API和静态资产的不同子域。这样,您就可以在www.mydomain.com上拥有静态资产,在API.mydomain.com拥有API(或使用相同的域并基于路径前缀,例如/API路由到后端或静态资源(

您可以添加一个过滤器来实现该功能。有关实现这种过滤器的dropwizard插件,请参阅https://github.com/xvik/dropwizard-guicey-ext/tree/master/guicey-spa.下面的独立示例代码在Kotlin中。

class SinglePageAppFilter : Filter {
    override fun doFilter(servletRequest: ServletRequest,
                          servletResponse: ServletResponse,
                          chain: FilterChain) {
        val request = servletRequest as HttpServletRequest
        val response = servletResponse as HttpServletResponse
        if (request.requestURI == "/" || request.requestURI.startsWith("/api")) {
            chain.doFilter(servletRequest, servletResponse)
        } else {
            val wrapper = ResponseWrapper(response)
            chain.doFilter(servletRequest, wrapper)
            val sc = wrapper.sc
            if (sc == HttpServletResponse.SC_NOT_FOUND) {
                request.getRequestDispatcher("/").forward(request, response)
            } else if (sc != null) {
                response.sendError(sc)
            }
        }
    }
    override fun init(filterConfig: FilterConfig) {}
    override fun destroy() {}
}
class ResponseWrapper(response: HttpServletResponse) : HttpServletResponseWrapper(response) {
    var sc: Int? = null
    override fun sendError(sc: Int) {
        this.sc = sc
    }
}
class MyApplication : Application<MyConfiguration>() {
    override fun initialize(bootstrap: Bootstrap<MyConfiguration>) {
        bootstrap.addBundle(AssetsBundle("/assets", "/", "index.html"))
    }
    override fun run(configuration: MyConfiguration, environment: Environment) {
        environment.servlets().addFilter("SinglePageAppFilter", SinglePageAppFilter())
            .addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*")
    }
}

最新更新