April 11, 2020
Estimated Post Reading Time ~

AEM, form Submission & Handling POST requests

In this article, I’ll be specifically talking about how to handle POST requests in AEM and what options we have.

Please note that Adobe has added more security around handling POST requests from AEM 6.x onwards to prevent CSRF attack. If you don’t configure AEM correctly, POST requests will not work even after using any of the methods explained in this article.  You can read more about security configurations and restriction at:

It is very common to use cases to have external applications POST some data to an AEM page (e.g. /content/en/home.html) or even submit a form (POST) to the same URL. But, as you know that in AEM POST works differently and any POST call to AEM is intercepted by Sling’s POST servlet (org.apache.sling.servlets.post.impl.SlingPostServlet).

In some cases org.apache.sling.servlets.post.impl.SlingPostServlet is very useful when you actually want to perform CRUD (create, read, update and delete) operation on JCR nodes. If you are interested in manipulating nodes in AEM and don’t want to deal with low-level JCR session and access right etc. then look at some simple but, very powerful examples at below URL:


Let’s go back to our original topic and define a use case for this article. Let’s say we have a page /content/en/home.html and the following are acceptance criteria:

1. GET requests should render the original page as HTML (/content/en/home.html).
2. POST request to the same page should also render the same page and should persist the original request object (request parameters etc.)
3. The external application should be able to POST data to /content/en/home.html and we should be able to access it via request.getParameter(“WHATEVER_PARAM_NAME”)

Out of box first use case just works without any customizations. But, if you try to POST something to the same URL you’ll not get the expected result because Sling’s POST servlet will intercept the request and will think we are trying to perform some CRUD operation but that is not what we want in this case.

Sling provides a very useful utility to check which script/servlet will be invoked and if there are multiple eligible servlets that can handle the request then what will be the order. On your author instance navigate to below URL and enter any URL and choose request method (GET, POST, etc.) and click resolve. The result will show a list of servlets and their order.


By default the order of POST request processing is as follows:
1. com.adobe.granite.rest.impl.servlet.DefaultServlet (OptingServlet)
2. org.apache.sling.servlets.post.impl.SlingPostServlet
3. org.apache.sling.jcr.webdav.impl.servlets.SlingWebDavServlet

So, what options we have?
1. Create a Sling servlet
2. Add a POST.jsp at the template level and update form action so that it points to jcr:content e.g. (/content/en/home/jcr:content.html).  We need to add jcr:content in URL because this is the node where we have sling:resourceType defined which will tells sling’s resolver where our POST.jsp is sitting that is capable of handling POST request. If we don’t include jcr:content in the path then Sling’s POST servlet will handle the request.
3. Just include “.external”  (e.g.  (/content/en/home.external.html) selector to your POST request URL. Does this sound simple? Yes, it is.

I’ll not explain the first 2 options as you can find ample of examples for those 2 options on the internet. I am going to talk about the power of the 3rd option in this article. So how do this works?

In AEM every page (.html) has a primary type jcr:primaryType = cq: Page and there are set of scripts that are mapped with this primary type which intercepts the request and renders a page differently based on factors like selector, type of request method (by default only GET is handled), etc. You can find these mapping scripts for cq:Page under the folder /libs/foundation/components/primary/cq/Page. One of the scripts under this folder is external.POST.jsp and this is the script which is responsible for handling a POST request with “.external” selector. If you look at the implementation of external.POST.jsp you’ll notice that implementation is very simple, it just creates a wrapper around existing POST request and overrides the getMethod() method of SlingHttpServletRequestWrapper class so that it returns GET and forward control page URL (by removing selector) with this wrapped request and response object.

The very simple but powerful technique when you want to handle both GET and POST requests coming to a page.



By aem4beginner

No comments:

Post a Comment

If you have any doubts or questions, please let us know.