URL Mapping and Deep Linking

A strength of Sling is the automatic and expected way that resources are structured and exposed in a logical, ordered manner. For example, AEM, by configuration allows page access through the /content/ directory. A typical page URL would be access with a browser visit to /content/projectname/pagename/subpagename.html. The minimal effort in maintaining this structure has its benefits, but changing that structure to fulfill business needs can be troublesome. Thankfully, AEM provides a number of tools and techniques to do so. This text will explore some of those options.

Root Mapping: The most common change is the need to hide the /content/ node or at least offer top-level pages at the root level. So, instead of a user typing “http://mycompany.com/content/myproject/home.html,” they should be able to type “http://mycompany.com/” to reach the home page.

Normally, in a production environment, this is configured in front-facing web server like Apache with some configuration in the httpd.conf file using mod_rewrite. But it can also be done in AEM with some OSGi configuration:

root_mapping

Open Tools
Open OSGi Console
Search for and open Day CQ Root Mapping
Change the Traget (sic) Path property to whereever you'd like the redirect

Tip 1: If you like the old CQ5.5 dev landing page compared to AEM5.6, change projects.html to welcome.html

Tip 2: Other mechanisms for remapping URLs, which are discussed in this article, will break author instances because it interferes with things like authentication. Use the method above, which is safe, to remap the root node

Page Redirects: Sometimes pages are meant to simply be ways of grouping subpages, and not locations that a user should land on directly. These kind of pages can be set up as redirect component. A good example is the /content/geometrixx sample page.

page_redirect

To recreate this page redirect, either set it up when creating the page in AEM’s site builder (under New Page -> Advanced -> Redirect), or just change the properties of that page in CRX:

expand the content/{page} node
Click the ./jcr:content node
Change the sling:resourceType property to be foundation/components/redirect
Add a new String property called redirectTarget
Give redirectTarget a value of the new page (e.g. /content/myproject/mypage/mysubpage)

Tip 1: If a site is being built in one language, there’s no need to mimic the /en/ structure shown in the geometrixx example.

Tip 2: The sling extension (e.g. .html) will automatically carry over to the redirect page, and shouldn’t be specified

sling:Mapping Redirects: AEM’s most powerful URL-manipulation feature, a set of redirect components, is often overlooked because application servers don’t traditionally have this ability. But CQ’s built in Vanity URL support, namespace mangling, and internal tools all make use of this ability. A custom application can too, for instance, by remapping all /content project to /content/myproject

In CRX, navigate to the /etc/map node.
Open (or create) the http node of type sling:Folder
Create a node called content of type sling:Mapping
Add a property called sling:match and give it a value of localhost.4502/content/
Add a property called sling:internalRedirect and give it a value of /content/myproject

Now navigate to http://localhost:4502/content/mypage.html. The browser will display the URL that was entered, but internally AEM will be referencing the mapped directory structure.

Another way to test how CQ is handling mapping is by opening the Sling Resource Resolver tool. Log in with normal admin credentials (the default being admin/admin), enter http://localhost:4502/content/mypage.html into the test box, click Resolve and examine the “path” property that is output below the test box.

Problem: Remappping all of /content will also remap /content/dam, breaking current links

Solution: Override that particular mapping to point to itself

Within CRX, navigate to the /etc/map/http node.
Create a node called content_dam of type sling:Mapping
Add a property called sling:match and give it a value of localhost.4502/content/dam/
Add a property called sling:internalRedirect and give it a value of /content/dam/

This node will point to itself, and override the above /content/ mapping. The mapping rule resolution I believe is determined by string length and can be manipulated with sling:OrderedFolder. If readers have experience with this, please add comments below. It hasn’t been necessary to experiment with this feature for my projects.

The above problem will be more apparent if, instead of /content/ being mapping to the content directory, the root directory is also mapped.

Tip: Do not remap the root directory using this technique. There is a better technique above

While I recommend against remapping the root directory on author instances, as it will break things like authentication and CRX, it can still be done. In which case, the following directories also need to be remapped to point to themselves:

\apps\
\content\dam\
\etc\
\home\
\libs\
\tmp\
\var\

This should allow most applications and features of AEM to still work. But some monitoring of the app should take place to make sure other locations are not inappropriately being remapped.

Tip: If there’s a question about which URLs are being accessed by browsers or CRX, a tool like Fiddler can monitor and report on it.

Dynamic Redirects: Thankfully, both the sling:match and sling:internalRedirect nodes use regular expressions, so that URL mapping can be more dynamic. So things like top-level links can be remapped to strip off the “.html” extension.

Within /etc/map/http
Create a new node named posts of type sling:Mapping
Add a property called sling:match with value localhost.4502/posts/([^/]+)$
Add a property called sling:internalRedirect with value /content/myproject/posts/$1.html

This will allow posts to be accessed without an extension. There are other ways of performing this particular task, such as adding a GET.jsp entry to the components, but mapping redirects are the best way to not interfere with the rest of the Sling resolution logic.

Deep Linking: When taking advantage of dynamic sling:Mappings with regular expressions, URL deep-linking can be implemented without the use of URL parameters or javascript. In some cases, SEO (Search Engine Optimization) experts will advise that sub-pages be reached from URLs and get loaded on the initial request. Other needs like analytics engines might preclude the use of hash tags or URL parameters. In this case, AEM can leverage URL mappings and selectors to pass information to a component and preload content.

In the posts node above, for instance, we can instead change the mapping from going to post sub pages to the posts page directly. Here, assume there is some component inside the post page that loads properties from its child page. But it needs to know which child page is being accessed.

Add a property called sling:match with value localhost.4502/posts/([^/]+)$
Add a property called sling:internalRedirect with value /content/myproject/posts.$1.html

The mapping above will take a request to /posts/child-page-name, and remap it to /posts.child-page-name.html. Essentially, this is the same as a posts.html call, with the addition of a component now being able to use the sling Resource API to extract that selector. The code within such a component would look something like this:

posts.jsp

Tip 1: The dollar sign ($) above tells the regex “this is the end of the string. AEM therefore won’t map any URL with additional characters in the URL. However, URL parameters and hash tags will be ignored for the purposes of mapping, and don’t need to be considered

Tip 2: The technique demonstrated above will extract selectors from a page. Multiple can be stacked with additions /([^/]+) references in the sling:match property, and $2, $3… variable references in the sling:match property

Tip 3: Selectors can also be added to components using sling:include tags. To get a parent resource containing that information, use componentContent.getResource() in place of the currentPage.adaptTo(Resource.class) reference above

Summary: CQ offers a number of techniques to remap pages and URLs. While most of this can and should be done on a proxy web server, some powerful mapping tools are available directly in CQ. The topic is only superficially covered here, and any shared experiences or tips from readers are welcome in the comments below.

15 thoughts on “URL Mapping and Deep Linking

  1. Arun Sharma

    Hi Nick Matelli ,

    Thanks for giving above knowledge it is helpful but
    i want to change my “http://localhost:4502/” with a specific url so what i do pls suggest
    thanks in advance

    Reply
  2. Buster

    How about using sling to handle redirects of something like user sessions in your publish instance? Say for example, hitting the my-account.html page while not logged in, and having it redirect you to the login.html page because you have no session established? Or is there a better way to handle this? Really could be something other than an established session. Like for instance if you try to get to a checkout review page before having gone through the shipping/billing page.

    Reply
  3. Vidya

    I want to change my URL /content/kriya/global/en/home.html
    In this URL i could not add content. I am wan’t use vanity Url also.
    If you have any chance how can solve this problem please let me know

    Reply
    1. Nick MatelliNick Matelli Post author

      Either of the methods listed above should work fine. Are you having trouble with those?

      While AEM has the ability to do this, typically URL rewrites are done at the web server level. For instance, if you’re using apache, you’d use the mod_rewrite module.

      Reply
  4. smita

    Hi,
    I want to redirect user on different pages based on name value pair of url. eg. localhost:4502/content/******/*.html?site=abc.
    I have to redirect users to abc page.

    Please help

    Reply
  5. Francois Cournoyer

    Quick question, let’s say I need to have 2 instances on the same domain and that I’m using Apache virtual host as proxy.

    Let’s say the 1st Site select is BANANA
    NameVirtualHost mywebsite.com:80

    ServerName mywebsite.com
    documentRoot “C:/www”

    Allow from all

    RewriteEngine on
    RewriteRule “^/BANANA/(.*)” “http://my.cq.instance.ip:4502/$1” [P]

    This in theory almost works, but the problem is that on the AEM instance, it automatically removes the “BANANA” from the url for everthing.

    how would I go to avoid this, how could I tell CQ to keep the “BANANA” in this case?

    Reply
    1. Nick MatelliNick Matelli Post author

      Hi Francois,

      If I understand correctly, you’re saying the RewriteRule is what’s failing to preserve the string “BANANA”? That would make sense because the $1 is only capturing what’s in the parentheses, and not the hardcoded string before it. Perhaps add that hardcoded value to both sides of the rule:

      RewriteRule “^/BANANA/(.*)” “http://my.cq.instance.ip:4502/BANANA/$1″ [P]

      Or add another set of parenthesis if this isn’t a hardcoded value. Something like this (but test the syntax first):

      RewriteRule “^/(BANANA)/(.*)” “http://my.cq.instance.ip:4502/$1/$2″ [P]

      If I’m misunderstanding the problem, and the BANANA portion of your URL is being lost earlier in the process, let me know. We’d then need to look into more configuration details to solve this.

      Reply
  6. Shalini

    Hi Nick,

    I want to add multiple regular expressions as per the project requirement.
    Is there a way the order in which the expressions get processed can be defined?

    Thanks
    Shalini

    Reply
  7. ronnyfm

    I am facing an issue with DAM rewrite. I am getting 404. Could you post the complete DAM configuration? Please.

    Reply
  8. Brendan French

    Hey Nick,

    Great Article! I had a question that I’ve been having an issue with.
    I am running a default AEM 6.3 author and publish instance (paths are aem/author and aem/publish and everything seems to work fine, however when I installed communities things started breaking….

    When I start navigating around in communtities the url path gets changed from aem/author/communities to just /communities. Do you know why this is happening?

    I am also running Tomcat as the webserver

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *