Struts2 .action extension causing CSS, JavaScript and Struts Dojo to break

We have been running on Struts 2.1.8 for some time and all Struts actions have been working as expected, i.e. href's to the Struts actions are rendered with the action name with no extension.

Here is the JSP code that set's up the links:

<ul id="top_menu">
  <li id="itemHome" class="active"><s:a action="viewHome">Home</s:a></li>
  <li><s:a action="viewSearch">Search</s:a></li>
  <li><s:a action="viewBookMarks">My Bookmarks</s:a></li>
  <li><s:a action="viewSupport">Support</s:a></li>
</ul>

The links rendered correctly to http://localhost/viewHome, http://localhost/viewSearch, etc. under 2.1.8

We just upgraded to Struts 2.2.1 (an have checked all versions from this up to v2.3.4.1) and are now seeing Struts actions links are rendering as http://localhost/viewHome.action, http://localhost/viewSearch.action, etc.

My research has shown that the general suggested solution is to use

<constant name="struts.action.extension" value=""/>

in struts.xml to remove the .action suffix. Whilst this makes the URLs render correctly it is causing an unexpected side effect. Struts now thinks every URL is an action including requests for .css, .png, etc.

My filter-mapping in web.xml has not changed. And although it sends /* to Struts we didn't see this behavior under 2.1.8

<filter>
   <filter-name>struts2</filter-name>
   <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>   
</filter>

<filter-mapping>
   <filter-name>struts2</filter-name>
   <url-pattern>/*</url-pattern>
</filter-mapping>

To counteract this I've had to use the excludePattern to stop Struts trying to treat these requests as actions.

<constant name="struts.action.excludePattern" value="/index.html,/images/.*,/js/.*,/css/.*"/>

Whilst this works, the last hurdle is that my logs are full of errors from Struts tags requests that are being handled as Struts actions. When I add these URI's to the exclude pattern then Struts Dojo tags don't seem to be working in some pages.

The parts of struts.xml affected are:

<constant name="struts.devMode" value="true" />
<!-- Set URL's to have no .action extension -->
<constant name="struts.action.extension" value=""/>
<constant name="struts.action.excludePattern" value="/index.html,/images/.*,/js/.*,/css/.*"/>

And an example of the Struts errors in the log is:

2012-09-26 17:12:57,984 [http-bio-8080-exec-9] ERROR org.apache.struts2.dispatcher.Dispatcher- Could not find action or result
/struts/dojo/struts_dojo.js
There is no Action mapped for namespace [/] and action name [struts_dojo.js] associated with context path []. - [unknown location]
    at com.opensymphony.xwork2.DefaultActionProxy.prepare(DefaultActionProxy.java:185)
    at org.apache.struts2.impl.StrutsActionProxy.prepare(StrutsActionProxy.java:63)
    at org.apache.struts2.impl.StrutsActionProxyFactory.createActionProxy(StrutsActionProxyFactory.java:39)
    at com.opensymphony.xwork2.DefaultActionProxyFactory.createActionProxy(DefaultActionProxyFactory.java:58)
    at org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:501)
    at org.apache.struts2.dispatcher.ng.ExecuteOperations.executeAction(ExecuteOperations.java:77)
    at org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:91)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:225)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:927)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1001)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:579)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:680)

I'm not sure if the struts Dojo requests are real URI's or virtual or something else.

It feels at this point that I've jumped through quite a few hoops to fix what is essentially a simple problem of removing the .action extension from URL's given that going back to the 2.1.8 JAR solves everything but I'm determined to find a way forward if possible.

Any help is very much appreciated.


Try to use struts action exstension with comma like this
<constant name="struts.action.extension" value=","/>.
From the struts2 properties file:

Used by the DefaultActionMapper You may provide a comma separated list, e.g. struts.action.extension=action,jnlp,do The blank extension allows you to match directory listings as well as pure action names without interfering with static resources, which can be specified as an empty string prior to a comma e.g. struts.action.extension=, or struts.action.extension=x,y,z,, struts.action.extension=action,,