How to get grails 3.x to respond to an OPTIONS request? - grails-3.0

In grails 2.x, we had to add this to the src/templates/war/web.xml in order for it to route an OPTIONS request. These types of requests are used when CORS is used.
<servlet>
<servlet-name>grails</servlet-name>
<servlet-class>org.codehaus.groovy.grails.web.servlet.GrailsDispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
<init-param>
<param-name>dispatchOptionsRequest</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
web.xml isn't used anymore in grails 3 so there must be a new way. I'm also curious why this option doesn't default on.

It appears the new way to configure is in resources.groovy:
import org.grails.web.servlet.mvc.GrailsDispatcherServlet
beans = {
// configure dispatch servlet so it dispatches OPTIONS requests
dispatcherServlet(GrailsDispatcherServlet) {
dispatchOptionsRequest = true
}
}

Related

Production deployment issue on Google App engine

I am using Google App engine and deployed web application.
I tried to deploy code on local using App engine then it is working fine
but when I deployed on Production server then it caused error.
Request : POST 20180909t164211-dot-spry-autumn-140509.appspot.com/_ah/spi/BackendService.getApiConfigs
(View request) Status : 500 Internal Server Error, Updated Screen shots for error and web.xml configration.
Web.xml configration:
<servlet>
<servlet-name>SystemServiceServlet</servlet-name>
<servlet-class>com.google.api.server.spi.SystemServiceServlet</servlet-class>
<init-param>
<param-name>services</param-name>
<param-value />
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>SystemServiceServlet</servlet-name>
<url-pattern>/_ah/spi/*</url-pattern>
</servlet-mapping>
Production error :
Please suggest me some solutions for same.
Endpoints v1 has been shut down. You must migrate your application to Endpoints v2. See migration instructions.

Migrating to Cloud Endpoints 2.0 - Working on localhost but not on App Engine

I'm migration my GAE Java app to Google Cloud Endpoints 2.0. I followed the migration guide (https://cloud.google.com/endpoints/docs/frameworks/legacy/v1/java/migrating) to migrate to Endpoints v2.0.
The endpoints service calls are working on localhost but returning 404 (Not Found) when uploaded to the App Engine. I'm using Guice.
The relevant section from my web.xml looks similar to this:
<filter>
<filter-name>guiceFilter</filter-name>
<filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>guiceFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>com.xyz.myapp.server.guice.MyAppGuiceServletContextListener</listener-class>
</listener>
<servlet>
<servlet-name>EndpointsServlet</servlet-name>
<servlet-class>com.google.api.server.spi.EndpointsServlet</servlet-class>
<init-param>
<param-name>services</param-name>
<param-value>com.xyz.myapp.server.endpoints.MyEP1,com.xyz.myapp.server.endpoints.MyEP2</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>EndpointsServlet</servlet-name>
<url-pattern>/_ah/api/*</url-pattern>
</servlet-mapping>
MyAppGuiceServletContextListener.java
public class MyAppGuiceServletContextListener extends GuiceServletContextListener {
#Override
protected Injector getInjector() {
return Guice.createInjector(new GuiceServletModule(), new EPServletModule());
}
}
EPServletModule.java
public class EPServletModule extends EndpointsModule {
#Override
protected void configureServlets() {
super.configureServlets();
Set<Class<?>> serviceClasses = new HashSet<Class<?>>();
serviceClasses.add(MyEP1.class);
serviceClasses.add(MyEP2.class);
configureEndpoints("/_ah/api/*", serviceClasses);
}
}
GuiceServletModule:
public class GuiceServletModule extends ServletModule {
#Override
protected void configureServlets() {
super.configureServlets();
serve("/myapp/servlet1").with(Servlet1.class);
serve("/myapp/servlet2").with(Servlet2.class);
}
}
I'm able to invoke the regular servlets at the paths:
https://[version]-dot-myapp-id.appspot.com/myapp/servlet1
https://[version]-dot-myapp-id.appspot.com/myapp/servlet2
But I'm not able to access the endpoints. It always returns 404 error code. I tried via my Javascript client and also via the APIs Explorer, and get the same error.
I also checked the logs and strangely the logs show the POST request like this:
"POST /_ah/spi/com.xyz.myapp.server.endpoints.MyEP1.myEPMethod HTTP/1.1" 404
Why does it start with /_ah/spi/ when my client is invoking it via /_ah/api/ ?
NOTE: I'm able to invoke the Endpoints 1.0, which are deployed on a different version of the same app, without any issue. But the Endpoints 2.0 version is not working.
Am I missing something?
I also have a very basic question. My client is Javascript based. Does it really make use of the Discovery Document?
I fixed this by Updating Android Studio to the latest version and updating the SDK.

Alternate servlet definition to web.xml?

I am using google app engine, and I define all my servlet paths in web.xml. Is there a way to define these in code instead of xml? I ask because the web.xml file is very verbose and I have many servlets. If I could register the servlets in java code somewhere I can probably shorten things.
Thanks
You can define a "main" servlet whose job it is to dispatch to other servlets; in your web.xml, you would write something like:
<web-app xmlns="http://java.sun.com/xml/ns/javaee" version="2.5">
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>com.mydomain.myapp.Dispatcher</servlet-class>
</servlet>
</web-app>
This would map /* (your entire app) to your dispatcher class. You could then register your various servlets with the dispatcher under different paths (e.g. you could use the Spring DispatcherServlet or your own).

Servlet-Filter is not honoured for welcome file

I am using a Filter do generate dynamicly content to be visible for webcrawlers (https://developers.google.com/webmasters/ajax-crawling/docs/specification). This filter is working fine if the incoming url contains a path (http://www.unclestock.com/app.jsp#!s=GOOG). If the incoming url contains just my domain (and a fragment), say http://www.unclestock.com#!s=GOOG, the welcome file (app.jsp) is returned, but the filter is not honnoured.
My web.xml contains the following filter map:
<filter-mapping>
<filter-name>crawler</filter-name>
<url-pattern>/app.jsp</url-pattern>
</filter-mapping>
<welcome-file-list>
<welcome-file>app.jsp</welcome-file>
</welcome-file-list>
I have tried to use an index.html welcome file instead, which redirects to app.jsp. The filter is then executed. However, this does not solve my problem: A client side redirect is not followed by the crawlers (which is the idea), and with server side redirect, I would loose my url fragment (which I also need).
Do you see any alternative solution?
I'm using Google Appengine.
I solved it by using a welcome servlet which does a RequestDispatcher forward. Note that the dispatcher FORWARD must be added to the filter-mapping in order to have the filter working during the foward.
web.xml:
<filter-mapping>
<filter-name>crawler</filter-name>
<url-pattern>*.jsp</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
<welcome-file-list>
<welcome-file>welcome</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>welcome</servlet-name>
<servlet-class>Welcome</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>welcome</servlet-name>
<url-pattern>/welcome</url-pattern>
</servlet-mapping>
Welcome.java:
public class Welcome extends RemoteServiceServlet {
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
RequestDispatcher rd = req.getRequestDispatcher("app.jsp");
rd.forward(req, resp);
}
}

redirect through web.xml in google-app-engine

After migrating to the new HRD store, I want to redirect requests to my old application to the new HRD application. I know I should let the Google migration tool make an alias, but since I migrate an intermediate copy of my app (because of the nightmares that migrating the database causes) that is not an option.
My plan was to use a servlet that does a HTTP 301 (HttpServletResponse.SC_MOVED_PERMANENTLY) redirect, and use a servlet-mapping with /* in web.xml.
This works locally, but on the real app-engine, it doesn't. It seems like there is no URL pattern that the app-engine correctly recognizes. So far I have:
<servlet-mapping>
<servlet-name>RedirectToHRD</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>RedirectToHRD</servlet-name>
<url-pattern>/*</url-pattern>
<url-pattern>/*/*</url-pattern>
<url-pattern>/*/*/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>RedirectToHRD</servlet-name>
<url-pattern>*.jsp</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>RedirectToHRD</servlet-name>
<url-pattern>index.jsp</url-pattern>
</servlet-mapping>
I know it looks crazy, but I was desperate. Only '/' and 'index.jsp' get redirected, through the RedirectToHRD servlet. For other pages (JSP or anything else) this does not work. The log file just happily indicates that the pages get served.
Can anyone tell me what is happening?
Edit:
I did what Peter Knego kindly suggested below, and made a filter. Now my web.xml has:
<filter-mapping>
<filter-name>RedirectToHRDFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
This still does not work on the 'real' appengine, and like the earlier attempt it does work locally.
My filter has the following method:
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)resp;
response.setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
String redirectURL = "http://fit20app-hrd.appspot.com"+request.getRequestURI();
if (request.getQueryString() != null) {
redirectURL += "?"+request.getQueryString();
}
response.setHeader("Location", redirectURL);
}
Now I am thinking that this filter may be broken, even though it works locally. On Google's servers it works for / and /index.jsp, but not for anything else.
This is solved, see comment below.
You can not have multiple <url-pattern> inside a <servlet-mapping>. Instead create multiple <servlet-mapping> with each having one <url-pattern> element.
Also, since you are trying to redirect everything you should use a servlet filter instead.

Resources