Last updated by abbruzzi 1 year ago
For Search Engine Optimization, it's preferable to align on a single
URL for a given page, rather than enabling multiple URLs to resolve to the
same content. Under Grails, it's very common to have multiple equivalent URLs.
One way to avoid negative impacts due to 'duplicate content' is to
add 'canonical' link tags to each page. See the Google Blog for more details:
http://googlewebmastercentral.blogspot.com/2009/02/specify-your-canonical.htmlShow Canonical
This plugin makes it easy to add 'canonical' link tags to each page in a Grails
application. After installing the plugin, the following tag can be added
to the <head> section of a layout (or wherever head metadata is managed):
<head>
…
<canonical:show />
…
</head>
This will map the current controller, action and paramters back to a
'canonical' URL, taking UrlMappings into consideration. For requests without
a controller and action, the actual request URI is assumed to be the desired
canonical (this can be disabled). It orders the query parameters,
so that pages with the same parameters displayed in a different order display the same tag.
It also uses the absolute URL, to address differences that may arise when two different
domain names resolve to the same application pages.
This is all that may be required, but the plugin enables some other refinements.
CAUTION: This plugin generates absolute URLs for the canonical tags.
Confirm that your grails.serverURL is set properly, such that
absolute URLs are being properly constructed.
Exclude Params
In some cases, query parameters are material to the page content, such as
an ID parameter. In other cases, the qeury parameter may be required for
operations, but is not material to the page content and should be 'ignored' by
search engines. In the latter case, these parameters can be excluded from
the 'canonical' URLs. The exclusion statement can be applied to all requests by,
for example, including it in a global layout. Or, it can be called in a
controller or template to apply to a smaller set of requests. To exclude
parameters use the following in a layout or template:
<canonical:exclude params="['session', 'source']" />
View Mappings
For view mappings, there is no controller and action involved.
Therefore=, reverse resolution of the 'canonical' URL is not possible.
In these cases, the URI can be set directly (see below), the URL can be
resolved based on the current request (see below), or, a parameter can
be added to the mapping which will be used as the base URI. The query String
is rebuilt (and properly escaped) from the request, and parameter exclusions
are applied. For a mapping in URLMappings.groovy, the feature can be used in this
fashion:
"/index"(view:"/index", canonical:"/")
Resolve from Request
If there is no action/controller pair, and no canonical paramter set from
URLMappings.groovy, the plugin will try to determine the path using the
current request. The path will be built from the HttpServletRequest, the parameters
will be built from the current parameter list, and exlcusions applied.
The query parameters are then URL-escaped and attached to the path
This 'best guess' may work well in some systems, and abysmally in others.
It can be fully disabled by setting:
plugins.canonical.disableResolveFromRequest = true
If turned off, the direct URI set method can still be used to apply canoncial URLs
to requests of this type.
Set URI
Finally, in some cases it may be preferable to override automatuc resolution
of the canonical URL with a specific URI. In this case, use the following
in the page template (or the equivalent from a controller):
<canonical:set uri="/some/other/place" />
Note that this is a true override:
no query string building, parameter exclusions or URL escaping is applied: the URI is used
exactly as provided.
Examples
Here are some examples of typically equivalent URLs, and how they map to a
single canonical URL:
Given a controller called 'example' and an action called 'simple', and the
common mappping:
"/$controller/$action?/$id?"{
constraints {
// apply constraints here
}
}The following URIs:
/example/simple
/example/simple/
/example/simple.html
/example?action=simple
would resolve to:
<link rel="canonical" href="http://www.domain.com/example/simple"/>
Due to parameter ordering, the following URIs:
/example/simple?a=1&z=2
/example/simple?z=2&a=1
would both resolve to:
<link rel="canonical" href="http://www.domain.com/example/simple?a=1&z=2"/>
Given a mapping like:
"/someMapping/$id"{
controller: 'example', action: 'mapped'
}The following URIs:
/example/mapped?id=extra
/example/mapped/extra
/someMapping/extra
would all resolve to:
<link rel="canonical" href="http://www.domain.com/someMapping/extra"/>
For an exclusion list containing 'session' and 'source',
the following URIs:
/example/simple?a=1&source=fb&z=2
/example/simple?z=2&session=12345&a=1&source=fb
would both resolve to:
<link rel="canonical" href="http://www.domain.com/example/simple?a=1&z=2"/>
Note that if you are externally rewriting URLs outside of UrlMappings,
using a tool such as mod_rewrite, this plugin may not produce the desired result:
the plugin is unaware of those rewrites.