从Jhipster中的URL(包括Java和angular 6)中删除哈希(#) [英] Remove hash (#) from URL in Jhipster (both java and angular 6)

查看:103
本文介绍了从Jhipster中的URL(包括Java和angular 6)中删除哈希(#)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Jhipster Spring boot + angular6.但是由于URL中的hash(#),我遇到了麻烦.它正在影响SEO.

I am using Jhipster Spring boot + angular 6. But i'm having trouble because of the hash(#) in URL. It is affecting SEO.

我尝试在app-routing-module.ts中设置useHash: false. 但是然后当我通过npm start运行项目时,API无法正常工作.

I tried setting useHash: false in app-routing-module.ts. But then the API is not working when I run the project via npm start.

我认为我必须更改Java文件中的某个位置,以从URL中删除#.

I think somewhere in Java files I have to change a configuration to remove # from the URL.

这是我的WebConfigurer代码,

Here is my WebConfigurer code,

@Configuration
public class WebConfigurer implements ServletContextInitializer, WebServerFactoryCustomizer<WebServerFactory> {

    private final Logger log = LoggerFactory.getLogger(WebConfigurer.class);

    private final Environment env;

    private final JHipsterProperties jHipsterProperties;

    private MetricRegistry metricRegistry;

    public WebConfigurer(Environment env, JHipsterProperties jHipsterProperties) {

        this.env = env;
        this.jHipsterProperties = jHipsterProperties;
    }

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        if (env.getActiveProfiles().length != 0) {
            log.info("Web application configuration, using profiles: {}", (Object[]) env.getActiveProfiles());
        }
        EnumSet<DispatcherType> disps = EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD, DispatcherType.ASYNC);
        initMetrics(servletContext, disps);
        log.info("Web application fully configured");
    }

    /**
     * Customize the Servlet engine: Mime types, the document root, the cache.
     */
    @Override
    public void customize(WebServerFactory server) {
        setMimeMappings(server);

        /*
         * Enable HTTP/2 for Undertow - https://twitter.com/ankinson/status/829256167700492288
         * HTTP/2 requires HTTPS, so HTTP requests will fallback to HTTP/1.1.
         * See the JHipsterProperties class and your application-*.yml configuration files
         * for more information.
         */
        if (jHipsterProperties.getHttp().getVersion().equals(JHipsterProperties.Http.Version.V_2_0) &&
            server instanceof UndertowServletWebServerFactory) {

            ((UndertowServletWebServerFactory) server)
                .addBuilderCustomizers(builder ->
                    builder.setServerOption(UndertowOptions.ENABLE_HTTP2, true));
        }
    }

    private void setMimeMappings(WebServerFactory server) {
        if (server instanceof ConfigurableServletWebServerFactory) {
            MimeMappings mappings = new MimeMappings(MimeMappings.DEFAULT);
            // IE issue, see https://github.com/jhipster/generator-jhipster/pull/711
            mappings.add("html", MediaType.TEXT_HTML_VALUE + ";charset=" + StandardCharsets.UTF_8.name().toLowerCase());
            // CloudFoundry issue, see https://github.com/cloudfoundry/gorouter/issues/64
            mappings.add("json", MediaType.TEXT_HTML_VALUE + ";charset=" + StandardCharsets.UTF_8.name().toLowerCase());
            ConfigurableServletWebServerFactory servletWebServer = (ConfigurableServletWebServerFactory) server;
            servletWebServer.setMimeMappings(mappings);
        }
    }

    /**
     * Initializes Metrics.
     */
    private void initMetrics(ServletContext servletContext, EnumSet<DispatcherType> disps) {
        log.debug("Initializing Metrics registries");
        servletContext.setAttribute(InstrumentedFilter.REGISTRY_ATTRIBUTE,
            metricRegistry);
        servletContext.setAttribute(MetricsServlet.METRICS_REGISTRY,
            metricRegistry);

        log.debug("Registering Metrics Filter");
        FilterRegistration.Dynamic metricsFilter = servletContext.addFilter("webappMetricsFilter",
            new InstrumentedFilter());

        metricsFilter.addMappingForUrlPatterns(disps, true, "/*");
        metricsFilter.setAsyncSupported(true);

        log.debug("Registering Metrics Servlet");
        ServletRegistration.Dynamic metricsAdminServlet =
            servletContext.addServlet("metricsServlet", new MetricsServlet());

        metricsAdminServlet.addMapping("/management/metrics/*");
        metricsAdminServlet.setAsyncSupported(true);
        metricsAdminServlet.setLoadOnStartup(2);
    }

    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = jHipsterProperties.getCors();
        if (config.getAllowedOrigins() != null && !config.getAllowedOrigins().isEmpty()) {
            log.debug("Registering CORS filter");
            source.registerCorsConfiguration("/api/**", config);
            source.registerCorsConfiguration("/management/**", config);
            source.registerCorsConfiguration("/v2/api-docs", config);
        }
        return new CorsFilter(source);
    }

    @Autowired(required = false)
    public void setMetricRegistry(MetricRegistry metricRegistry) {
        this.metricRegistry = metricRegistry;
    }
}

这是我的AngularRouteFilter servlet代码,

Here is my AngularRouteFilter servlet code,

public class AngularRouteFilter extends OncePerRequestFilter {

    // add the values you want to redirect for
    private static final Pattern PATTERN = Pattern.compile("^/((api|swagger-ui|management|swagger-resources)/|favicon\\.ico|v2/api-docs).*");

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain)
        throws ServletException, IOException {
        if (isServerRoute(request)) {
            filterChain.doFilter(request, response);
        } else {
            RequestDispatcher rd = request.getRequestDispatcher("/");
            rd.forward(request, response);
        }
    }

    protected static boolean isServerRoute(HttpServletRequest request) {
        if (request.getMethod().equals("GET")) {
            String uri = request.getRequestURI();
        if (uri.startsWith("/app")){

                return true;
            }
            return PATTERN.matcher(uri).matches();
        }
        return true;
    }
}

这是我的Swagger index.html(swagger-ui/index.html)

here is my Swagger index.html(swagger-ui/index.html)

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Swagger UI</title>
    <link rel="icon" type="image/png" href="images/favicon-32x32.png" sizes="32x32" />
    <link rel="icon" type="image/png" href="images/favicon-16x16.png" sizes="16x16" />
    <link href='./dist/css/typography.css' media='screen' rel='stylesheet' type='text/css'/>
    <link href='./dist/css/reset.css' media='screen' rel='stylesheet' type='text/css'/>
    <link href='./dist/css/screen.css' media='screen' rel='stylesheet' type='text/css'/>
    <link href='./dist/css/reset.css' media='print' rel='stylesheet' type='text/css'/>
    <link href='./dist/css/print.css' media='print' rel='stylesheet' type='text/css'/>
    <script src='./dist/lib/object-assign-pollyfill.js' type='text/javascript'></script>
    <script src='./dist/lib/jquery-1.8.0.min.js' type='text/javascript'></script>
    <script src='./dist/lib/jquery.slideto.min.js' type='text/javascript'></script>
    <script src='./dist/lib/jquery.wiggle.min.js' type='text/javascript'></script>
    <script src='./dist/lib/jquery.ba-bbq.min.js' type='text/javascript'></script>
    <script src='./dist/lib/handlebars-4.0.5.js' type='text/javascript'></script>
    <script src='./dist/lib/lodash.min.js' type='text/javascript'></script>
    <script src='./dist/lib/backbone-min.js' type='text/javascript'></script>
    <script src='./dist/swagger-ui.min.js' type='text/javascript'></script>
    <script src='./dist/lib/highlight.9.1.0.pack.js' type='text/javascript'></script>
    <script src='./dist/lib/highlight.9.1.0.pack.js' type='text/javascript'></script>
    <script src='./dist/lib/jsoneditor.min.js' type='text/javascript'></script>
    <script src='./dist/lib/marked.js' type='text/javascript'></script>
    <script src='./dist/lib/swagger-oauth.js' type='text/javascript'></script>

    <!-- Some basic translations -->
    <!-- <script src='lang/translator.js' type='text/javascript'></script> -->
    <!-- <script src='lang/ru.js' type='text/javascript'></script> -->
    <!-- <script src='lang/en.js' type='text/javascript'></script> -->

    <script type="text/javascript">
        $(function() {
            var springfox = {
                "baseUrl": function() {
                    var urlMatches = /(.*)\/swagger-ui\/index.html.*/.exec(window.location.href);
                    return urlMatches[1];
                },
                "securityConfig": function(cb) {
                    $.getJSON(this.baseUrl() + "/swagger-resources/configuration/security", function(data) {
                        cb(data);
                    });
                },
                "uiConfig": function(cb) {
                                    alert(cb);

                    $.getJSON(this.baseUrl() + "/swagger-resources/configuration/ui", function(data) {
                        cb(data);
                    });
                }
            };
            window.springfox = springfox;
            window.oAuthRedirectUrl = springfox.baseUrl() + './dist/o2c.html'

            window.springfox.uiConfig(function(data) {
                window.swaggerUi = new SwaggerUi({
                    dom_id: "swagger-ui-container",
                    validatorUrl: data.validatorUrl,
                    supportedSubmitMethods: ['get', 'post', 'put', 'delete', 'patch'],
                    onComplete: function(swaggerApi, swaggerUi) {
                        initializeSpringfox();
                        if (window.SwaggerTranslator) {
                            window.SwaggerTranslator.translate();
                        }
                        $('pre code').each(function(i, e) {
                            hljs.highlightBlock(e)
                        });
                    },
                    onFailure: function(data) {
                        log("Unable to Load SwaggerUI");
                    },
                    docExpansion: "none",
                    apisSorter: "alpha",
                    showRequestHeaders: false
                });

                initializeBaseUrl();

                $('#select_baseUrl').change(function() {
                    window.swaggerUi.headerView.trigger('update-swagger-ui', {
                        url: $('#select_baseUrl').val()
                    });
                    addApiKeyAuthorization();
                });

                function addApiKeyAuthorization() {
                    var authToken = JSON.parse(localStorage.getItem("jhi-authenticationtoken") || sessionStorage.getItem("jhi-authenticationtoken"));
                    var apiKeyAuth = new SwaggerClient.ApiKeyAuthorization("Authorization", "Bearer " + authToken, "header");
                    window.swaggerUi.api.clientAuthorizations.add("bearer", apiKeyAuth);
                }

                function getCSRF() {
                    var name = "XSRF-TOKEN=";
                    var ca = document.cookie.split(';');
                    for(var i=0; i<ca.length; i++) {
                        var c = ca[i];
                        while (c.charAt(0)==' ') c = c.substring(1);
                        if (c.indexOf(name) !== -1) return c.substring(name.length,c.length);
                    }
                    return "";
                }

                function log() {
                    if ('console' in window) {
                        console.log.apply(console, arguments);
                    }
                }

                function oAuthIsDefined(security) {
                    return security.clientId
                    && security.clientSecret
                    && security.appName
                    && security.realm;
                }

                function initializeSpringfox() {
                    var security = {};
                    window.springfox.securityConfig(function(data) {
                        security = data;
                        if (typeof initOAuth === "function" && oAuthIsDefined(security)) {
                            initOAuth(security);
                        }
                    });
                }
            });

            function maybePrefix(location, withRelativePath) {
                var pat = /^https?:\/\//i;
                if (pat.test(location)) {
                    return location;
                }
                return withRelativePath + location;
            }

            function initializeBaseUrl() {
                var relativeLocation = springfox.baseUrl();

                $('#input_baseUrl').hide();

                $.getJSON(relativeLocation + "/swagger-resources", function(data) {

                    var $urlDropdown = $('#select_baseUrl');
                    $urlDropdown.empty();
                    $.each(data, function(i, resource) {
                        var option = $('<option></option>')
                        .attr("value", maybePrefix(resource.location, relativeLocation))
                        .text(resource.name + " (" + resource.location + ")");
                        $urlDropdown.append(option);
                    });
                    $urlDropdown.change();
                });

            }

        });
    </script>
</head>


<body class="swagger-section">
<div id='header'>
    <div class="swagger-ui-wrap">
        <a id="logo" href="http://swagger.io">swagger</a>

        <form id='api_selector'>
            <div class='input'>
                <select id="select_baseUrl" name="select_baseUrl"></select>
            </div>
            <div class='input'><input placeholder="http://example.com/api" id="input_baseUrl" name="baseUrl" type="text"/>
            </div>
        </form>
    </div>
</div>

<div id="message-bar" class="swagger-ui-wrap" data-sw-translate>&nbsp;</div>
<div id="swagger-ui-container" class="swagger-ui-wrap"></div>
</body>
</html>

这是docs.component.html

here is docs.component.html

<iframe src="swagger-ui/index.html" width="100%" height="900" seamless
    target="_top" title="Swagger UI" class="border-0"></iframe>

在这里,我的服务器代码在localhost:6060上运行良好. Butm localhost:6060/api/docs打开空白页.

here my server code is running perfectly @ localhost:6060. Butm localhost:6060/api/docs opening a blank page.

这是屏幕截图

请告诉我我做错了什么地方.

Please suggest me where i am doing wrong.

推荐答案

使用servlet过滤器的解决方案

第一步是配置客户端,在app-routing-module.ts

First step is to configure client, set useHash: false in app-routing-module.ts

index.html中,将<base href="./" />更改为<base href="/" />

但这还不够,因为它不支持深层链接,这意味着要从外部链接(例如来自邮件或另一个网站的链接)链接到客户端路由,或者在刷新浏览器中的页面时转向ve.

But it's not enough because it does not support deep linking which means linking to a client route from an external link like from a mail message or from another web site, or veen when refreshing page in browser.

当进行深层链接时,服务器会首先接收到请求,并且如果必须由客户端来处理URL,则将找不到该URL,因此我们的服务器应用必须检测URL是否必须由服务器按原样提供(例如,所有API调用)或转发到index.html,以便javascript应用可以对其进行解释.

When deep linking, the server receives the request first and if the URL has to be handled by client side, it will not be found so our server app must detect whether the URL has to be served as-is by server (e.g. all API calls) or forwarded to index.html so that the javascript app can interpret it.

一种解决方案是在我们在WebConfigurer.java中注册的servlet过滤器(Html5RouteFilter)中使用模式匹配.

One solution is to use pattern matching in a servlet filter (Html5RouteFilter) that we register in WebConfigurer.java

WebConfigurer.java

WebConfigurer.java


    @Bean
    public Html5RouteFilter html5RouteFilter() {
        return new Html5RouteFilter();
    }

Html5RouteFilter.java

Html5RouteFilter.java


package com.mycompany.myapp.web;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.regex.Pattern;

/**
 * Filter that distinguishes between client routes and server routes  when you don't use '#' in client routes.
 */
public class Html5RouteFilter extends OncePerRequestFilter {

    private Logger log = LoggerFactory.getLogger(getClass());


    // These are the URIs that should be processed server-side
    private static final Pattern PATTERN = Pattern.compile("^/((api|content|i18n|management|swagger-ui|swagger-resources)/|error|h2-console|swagger-resources|favicon\\.ico|v2/api-docs).*");

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain filterChain)
        throws ServletException, IOException {
        if (isServerRoute(request)) {
            filterChain.doFilter(request, response);
        } else {
            RequestDispatcher rd = request.getRequestDispatcher("/");
            rd.forward(request, response);
        }
    }

    protected static boolean isServerRoute(HttpServletRequest request) {
        if (request.getMethod().equals("GET")) {
            String uri = request.getRequestURI();
            if (uri.startsWith("/app")) {
                return true;
            }
            return PATTERN.matcher(uri).matches();
        }
        return true;
    }
}

这篇关于从Jhipster中的URL(包括Java和angular 6)中删除哈希(#)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆