Multiple domains with spring mvc

2020-05-19 00:24发布

问题:

Let's say I have an application that has to shorten URLs, but also do other things. (like google.com and goo.gl, or facebook.com and fb.me).

It will be easy to simply deploy two applications, but (for now) it's simpler to be just one. Using spring and spring-mvc. I have the following mappings:

@RequestMapping(value="/{shortUrlKey}", headers="Host=foo.br")
...
@RequestMapping(value="/{username}")

Alas, the headers annotation acts not as giving more specific information, but as restricting instead. So if I have these two, only the latter is invoked, even if I open it as http://foo.br/asdf. If leave only the former, it works for those coming from foo.br, and doesn't open anything if the host is different.

So, the questions:

  • how can I make two handlers for the same paths, but different URLs / Hosts
  • is it possible to resolve the host dynamically, with a property placeholder configurer (rather than hard-code it in the annotation)

Perhaps both would work if there is some pluggable mechanism for method resolution. Is there such?

回答1:

My immediate suggestion would be to write a servlet filter (or a Spring HandlerInterceptor), which would take the host name from the request, prepend it to the original requested path, then forward on the request.

For example, given the requested URL http://goo.gl/my/path, the filter would forward to /goo.gl/my/path. The Spring MVC mappings would then have something to get their teeth into. The ant-style wildcard syntax (e.g. "**/my/path") or path-variable style (e.g. "{requestHost}/my/path" might be helpful there.

Alternatively, the filter could set a custom header or request attribute containing the requested host, but that's probably less flexible.

I'm not sure what you mean by the second part of your question, though.

Here's a working snippet:

@Override
public boolean preHandle(HttpServletRequest request,
        HttpServletResponse response, Object handler) throws Exception {

    if (request.getRequestURL().toString().contains(shortenerDomain)
            && !request.getRequestURI().startsWith(SHORT_URI_PREFIX)) {

        request.getRequestDispatcher(SHORT_URI_PREFIX + request.getRequestURI())
                .forward(request, response);
        return false;
    } else {
        return true;
    }
}


回答2:

Based on your description, it sounds like you could have two controller methods with each domain header mapping:

@RequestMapping(value="/{shortUrlKey}", headers="Host=foo.br")
public void fooBr() { ... }

@RequestMapping(value="/{shortUrlKey}", headers="Host=bar.bz")
public void barBz() { ... }