UrlRewrite Not working for GAE/J - google-app-engine

Not sure what am i doing wrong, I am using http://www.tuckey.org/urlrewrite/#
1) put the jar file in lib directory
2) update web.xml with following code
<filter>
<filter-name>UrlRewriteFilter</filter-name>
<filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>UrlRewriteFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
3) copied urlrewrite.xml into the WEB-INF directory and added following rule
<rule enabled="true">
<from>^/view/([a-z]+)/([a-z]+)$</from>
<to>/view?id=$1&title=$2</to>
</rule>
<outbound-rule>
<from>^/view?id=([a-z]+)&title=([a-z]+)$</from>
<to>/view/$1/$2</to>
</outbound-rule>
4) Also updated my JSP page with following - (/view -> is servlet which redirects to view.jsp?id=123&title=my%20title)
<a href="<%= response.encodeURL("/view?id="+id+"&title="+title)%>">
my expectation was -- to generate URL inside HTML as well as browser window as follows ...
www.mywebsite.com/view/123/my-title
5) but really - my URL is becoming ->
so not sure what am i doing wrong so my URL is not getting rewritten friendly way.

Related

AngularJS remove # and have error when refresh page

I have AngularJS webapp and start it with Tomcat 7. Using $locationProvider.html5Mode(true) I remove hash '#' from url
localhost:8080/App/#/login -> localhost:8080/App/login
But now, when I refresh localhost:8080/App/login I have 404 error. How to configure Tomcat7 for localhost:8080/App/login refresh?
app.config:
$urlRouterProvider.otherwise("/login/");
$stateProvider
.state('home', {
abstract: true,
templateUrl: 'dist/view/home.html',
controller: 'HomeCtrl'
});
$locationProvider.html5Mode(true);
index.html:
<head>
<meta charset="utf-8">
<script>
document.write('<base href="' + document.location + '" />');
</script>
</head>
It's because when you do a full reload you always send a a request to the server with the current url. Since Angular has not loaded yet it can't handle the route, and the server doesn't know anything about what routes exist in angular and not
Without html5mode Angular uses fragmented urls of the type www.example.com/#/page. # was originally used for anchor-links so by convention the fragment part of the url is completely ignored by the server. To the server that above request would be the same as just www.example.com/, which is probably where you index.html is located. So reloading your page will in this case get your index.html, which will load Angular, which will in turn handle the fragment part of the url (#/page).
With html5mode however the fragment is hidden, and the url looks like a normal url, www.example.com/page. But when you reload the page the server doesn't get the fragment so it tries to find whatever is served under /page, which is probably nothing. Giving you a 404, Angular cannot load since index.html is not loaded, and you have a broken page.
The usual way to fix this is to have the server serve index.html under all urls that does not match a static asset (or the pattern of one). So if you request say an image it will find it and return it ok, but if you request /page (and it does not exist as a static asset) then it returns index.html. Then Angular will start, read the url and trigger the correct route.
I have only done this in nginx so I don't know how Tomcat would do it, but the principle should be the same.
1) Download urlrewritefilter-4.0.3.jar
2) Create WEB-INF folder in root directory where index.html is present.
3) Create lib folder in WEB-INF & put downloaded jar file into it.
4) Create web.xml file in WEB-INF . Put following code into it.
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1" metadata complete="true">
<display-name>Welcome to Tomcat</display-name><description>Welcome to Tomcat</description><welcome-file-list><welcome-file>index.html</welcome-file></welcome-file-list>
<filter>
<filter-name>UrlRewriteFilter</filter-name>
<filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class></filter><filter-mapping><filter-name>UrlRewriteFilter</filter-name><urlpattern>/*</url-pattern><dispatcher>REQUEST</dispatcher> <dispatcher>FORWARD</dispatcher></filter-mapping></web-app>
5) Create urlrewrite.xml file WEB-INF
put following code into it
<?xml version="1.0" encoding="utf-8"?><!DOCTYPE urlrewrite PUBLIC-//tuckey.org//DTD UrlRewrite 3.2//EN"
"http://tuckey.org/res/dtds/urlrewrite3.2.dtd"><urlrewrite>
<rule enabled="true">
<from>/[0-9_-a-zA-Z\/]+$</from>
<to>/%{context-path}/</to>
</rule>/urlrewrite>
This is using Tomcat 7 & Tucky's urlrewritefilter https://github.com/paultuckey/urlrewritefilter
#mhatch. To budle the routes to all go to index.html, you can try this rewrite rule :
<rule enabled="true">
<from>/[0-9_-a-zA-Z\/]+$</from>
<to>/%{context-path}/</to>
This worked for me.
If you want to remove the hash (#), you must use rewrite function in server to serve the index.html for all path. If not, you will always receive 404 error. It's mean you can redirect the 404 to index.html.
Apache: add a rewrite rule to the .htaccess file as show here:
RewriteEngine On
# If an existing asset or directory is requested go to it as it is
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f [OR]
RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -d
RewriteRule ^ - [L]
# If the requested resource doesn't exist, use index.html
RewriteRule ^ /index.html
NGinx: use try_files, as described in Front Controller Pattern Web Apps, modified to serve index.html:
try_files $uri $uri/ /index.html;
IIS: add a rewrite rule to web.config, similar to the one shown here:
<system .webserver="">
<rewrite>
<rules>
<rule name="Angular Routes" stopprocessing="true">
<match url=".*">
<conditions logicalgrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchtype="IsFile" negate="true">
<add input="{REQUEST_FILENAME}" matchtype="IsDirectory" negate="true">
</add></add></conditions>
<action type="Rewrite" url="/">
</action></match></rule>
</rules>
</rewrite>
</system>
In tomcat, you can add it into the web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<error-page>
<error-code>404</error-code>
<location>/</location>
</error-page>
</web-app>
After redirect the web path to index.html, the HTML5 History API will be used in Angular JS to control the web route. Our main task here is just let index.html be called in server.
1) AngularJS
$routeProvider
.when('/path', {
templateUrl: 'path.html',
});
$locationProvider
.html5Mode(true);
2) server side, just put .htaccess inside your root folder and paste this
ewriteEngine On
Options FollowSymLinks
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /#/$1 [L]
Cheers....
Erik Honn gives a good explanation of the logic. Here's how I solved it using Jersey and Tomcat 7 with Tucky's urlrewritefilter https://github.com/paultuckey/urlrewritefilter
Add dependency using Maven or download jar.
<dependency>
<groupId>org.tuckey</groupId>
<artifactId>urlrewritefilter</artifactId>
<version>4.0.3</version>
</dependency>
Add filter mappings to the web.xml file located in WEB-INF directory. This should be within the web-app tag.
<filter>
<filter-name>UrlRewriteFilter</filter-name>
<filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>UrlRewriteFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
Create a file in WEB-INF called urlrewrite.xml and add rerouting to index.html
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE urlrewrite PUBLIC "-//tuckey.org//DTD UrlRewrite 4.0//EN"
"http://www.tuckey.org/res/dtds/urlrewrite4.0.dtd">
<!--
Configuration file for UrlRewriteFilter
http://www.tuckey.org/urlrewrite/
-->
<urlrewrite>
<rule>
<from>^/titles$</from>
<to>index.html</to>
</rule>
<rule>
<from>^/authors$</from>
<to>index.html</to>
</rule>
<rule>
<from>^/courses$</from>
<to>index.html</to>
</rule>
<rule>
<from>^/account$</from>
<to>index.html</to>
</rule>
</urlrewrite>
Don't forget to relaunch so that the xml is configured. It would be great if someone knew a way to bundle the routes to all go to index.html rather than having to set individual rules.
Just write this in htaccess
RewriteEngine on
# Don't rewrite files or directories
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
# Rewrite everything else to index.html to allow html5 state links
RewriteRule ^ index.php [L]
I dont have an index.html i have index.php so i wrote index.php instead of index.html
Cheers!
I recently found a solution to this issue that doesn't involve switching to Apache2 with a .htaccess file.
In web.xml:
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<error-page>
<error-code>404</error-code>
<location>/rewrite-404.jsp</location>
</error-page>
Then create a new file in WebContent called rewrite-404.jsp:
<% response.setStatus(HttpServletResponse.SC_OK); %>
<%# include file="index.html" %>
This will cause existing files in WebContent to be served as usual, and all requests that would normally return a 404 error to return index.html instead with a 200 (OK) response code.

Objectify dependency in Android Studio 1.0

In Android Studio 1.0 when we generate Cloud Endpoints from Java Class then it adds necessary things in web.xml automatically,
the changes made by Android Studio in web.xml files are,
1.
<filter>
<filter-name>ObjectifyFilter</filter-name>
<filter-class>com.googlecode.objectify.ObjectifyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ObjectifyFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
2.
<param-value>ADDS ENDPOINTS HERE AUTOMATICALLY</param-value>
Which wasn't done before (In Android Studio 0.8.6). The problem is it fails to start the local server. It says ERROR 503 SERVICE_UNAVAILABLE. Now I checked the build log. Then I saw that it was throwing java.lang.ClassNotFoundException: com.googlecode.objectify.ObjectifyFilter exception.
So I added the line compile 'com.googlecode.objectify:objectify:5.0.3' in build.gradle. It worked fine then.
Also I noticed if I remove the following portion from web.xml, it also works fine.
<filter>
<filter-name>ObjectifyFilter</filter-name>
<filter-class>com.googlecode.objectify.ObjectifyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ObjectifyFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Now is that a bug? Or am I missing something? Also what are the Objectify and ObjectifyFilters? Why do we need them?
This is a bug. Thank you for letting us know. Objectify is a framework for persisting data to the cloud datastore, as you noticed, if you aren't using it you can simply remove the filter declaration and it should work fine.
Objectify is an API for the GAE datastore:
https://code.google.com/p/objectify-appengine/

Struts 2 GAE No action mapped for namespace [/]

I'm learning Struts 2 for a project requirement and I've met some issues.
Following this tutorial at:
http://www.mkyong.com/google-app-engine/google-app-engine-struts-2-example/
And what I've done extra:
Added an index.jsp into the war folder
Changed web.xml to
<?xml version="1.0" encoding="utf-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<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>
<listener>
<listener-class>com.mkyong.listener.Struts2ListenerOnGAE</listener-class>
</listener>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
Now, when I rebuild and loads
http://localhost:8888
Rather then seeing the content I should have in my index.jsp, I'm getting a
Error 404 There is no Action mapped for namespace [/] and action name [] associated with context path [].
Can someone point me to the right direction? I've seen some other similar questions in SO but their solutions do not work for this specific example of Struts 2 + GAE.
My struts.xml
<struts>
<package name="user" namespace="/User" extends="struts-default">
<action name="Login">
<result>pages/login.jsp</result>
</action>
<action name="Welcome" class="com.mkyong.user.action.WelcomeUserAction">
<result name="SUCCESS">pages/welcome_user.jsp</result>
</action>
</package>
</struts>
Folder structure
I cant post images so, http://i.imgur.com/KSPmaMr.png
Exact same libraries used for download
http://www[dot]mediafire[dot]com/?utliwvcmo63o8l7
ok ,i got your problem,
change your struts.xml to this
<struts>
<package name="default" extends="struts-default" namespace="/">
<action name="Login">
<result>pages/login.jsp</result>
</action>
<action name="Welcome" class="com.mkyong.user.action.WelcomeUserAction">
<result name="SUCCESS">pages/welcome_user.jsp</result>
</action>
</package>
</struts>
I guess this will work, because filterDispatcher search for struts.xml file in root folder if you put your struts.xml file in root directory.
#Eleazar I followed the mykong tutorial link that you mentioned in your question. There is no use of index.html as far as I see that tutorial. <welcome-list> file is used when the is no action mentioned on application startup.
On step:8 in that tutorial they has provided the url which is http://localhost:8888/User/Login.action you need to run the test. Its got nothing to do with file in welcome list...
UPDATE:
You are getting that error because you have added struts2 filter as /*, and your action namespace is for /User. There is not action namespace for /. Adding package with name="default" with namespace="/" i.e <package name="default" extends="struts-default" namespace="/"></package> will resolve you issue. It will hit <welcome-file>

Remove appstats from web.xml (Java)

it seems ridicolous, but I am unable to remove appstats.
If I remove the following from the web.xml:
<filter>
<filter-name>appstats</filter-name>
<filter-
class>com.google.appengine.tools.appstats.AppstatsFilter</filter-
class>
<init-param>
<param-name>logMessage</param-name>
<param-value>Appstats available: /appstats/details?
time={ID}</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>appstats</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
my static content is not accessible any more and produces a 404 error.
I narrowed it down to the filter and filter-mapping tags, since I
removed the other tags from
http://code.google.com/appengine/docs/java/tools/appstats.html
step by step.
Only if those specific tags remain in the web.xml, the static content
becomes inaccessible after deployment.
Last night I had strange errors in the logs which are linked to source
files of appstats.
Hopefully you guys can help me.
Greets
upscale
Did you also delete the servlet definition :
<servlet>
<servlet-name>appstats</servlet-name>
<servlet-class>com.google.appengine.tools.appstats.AppstatsServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>appstats</servlet-name>
<url-pattern>/appstats/*</url-pattern>
</servlet-mapping>
Also, if you included it, you should clean up your appengine-web.xml :
<admin-console>
<page name="Appstats" url="/appstats" />
</admin-console>

BlobStore Redirects being ignored by ServletModule wired servlets

After the blobstore handles the upload request of a file it redirects to the url it is given, in this case "/upload". If I configure the UploadServlet url in web.xml like this:
<servlet>
<servlet-name>uploadServlet</servlet-name>
<servlet-class>com.....servlet.UploadServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>uploadServlet</servlet-name>
<url-pattern>/upload</url-pattern>
</servlet-mapping>
It works. If I use Guice to wire the servlet:
serve("/upload").with(UploadServlet.class);
I get the error:
Problem accessing /upload. Reason:NOT_FOUND
It seems as though the com.google.inject.servlet.ServletModule does not handle redirects. Is there a way around this?
I have struggled with the same issue myself today. This solved my problem and may be related:
https://groups.google.com/forum/#!topic/google-appengine-java/oqfvEmZGrdw
In dev mode, the blobstore service uses
RequestDispatcher.forward() rather than an HTTP request:
<filter-mapping>
<filter-name>guiceFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
<filter-mapping>
<filter-name>guiceFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
Of course, may be too late for you but for others it might help :-)

Resources