I'm currently porting my GAE app to Python 2.7 and have come across some exciting things that I've slowly been able to figure out one at a time (Hello, aliased simplejson library!). However, I'm currently at a loss to explain this particular issue.
Whenever I navigate to the Admin Console (http://localhost:8080/_ah/admin), I get a 404 page. This is strange in itself (This was working just fine before), but it also isn't my custom 404 page. This makes me think this is based on the built-in handlers, but I'm not sure what could be the cause.
Other fun facts:
There's no attempts to handle /_ah/.* in my app.yaml or elsewhere
Nothing has changed in my app.yaml aside from the usual script-to-WSGI handler stuff
No usage of Federated Logins
Over time I've turned on almost all of the builtins
The app deploys correctly and without issue
I'm using the GAE Launcher on OSX (Minor, but it does have some odd quirks about it)
Update
It's probably easier just to show the console logs of what is coming out. This is after the app has fully started and I have attempted to navigate to the admin page twice (The IO Error is cute, and only happens the initial time):
[Master] [dev_appserver_multiprocess.py:650] INFO Running application mygaeapp on port 8081: http://localhost:8081
[Master] [dev_appserver_multiprocess.py:652] INFO Admin console is available at: http://localhost:8081/_ah/admin
[Master] [dev_appserver_multiprocess.py:901] DEBUG balancer to port 9000
[App Instance] [0] [py_zipimport.py:139] WARNING Can't open zipfile /Library/Python/2.7/site-packages/slimmer-0.1.30-py2.7.egg: IOError: [Errno 13] file not accessible: '/Library/Python/2.7/site-packages/slimmer-0.1.30-py2.7.egg'
[App Instance] [0] [py_zipimport.py:139] WARNING Can't open zipfile /Library/Python/2.7/site-packages/NoseGAE-0.2.0-py2.7.egg: IOError: [Errno 13] file not accessible: '/Library/Python/2.7/site-packages/NoseGAE-0.2.0-py2.7.egg'
[App Instance] [0] [recording.py:372] INFO Saved; key: __appstats__:012400, part: 67 bytes, full: 8780 bytes, overhead: 0.000 + 0.007; link: http://localhost:8081/_ah/stats/details?time=1331638312442
[App Instance] [0] [dev_appserver.py:2865] INFO "GET /_ah/admin HTTP/1.1" 404 -
[Master] [dev_appserver_multiprocess.py:901] DEBUG balancer to port 9000
[App Instance] [0] [recording.py:372] INFO Saved; key: __appstats__:020100, part: 67 bytes, full: 9196 bytes, overhead: 0.000 + 0.007; link: http://localhost:8081/_ah/stats/details?time=1331638320129
[App Instance] [0] [dev_appserver.py:2865] INFO "GET /_ah/admin HTTP/1.1" 404 -
[Master] [dev_appserver_multiprocess.py:901] DEBUG balancer to port 9000
In case you found this answer and you're using App Engine SDK 1.7.6 or higher, the default URL has changed from localhost:8080/_ah/admin to localhost:8000.
So I finally tracked this down to something that works perfectly fine in Python 2.5, but breaks on Python 2.7 with dev_appserver only.
To turn maintenance mode on and off, we reassign the routes in the WSGI instance to point to a new set of URLs by changing the app.router field directly. Disabling this code path by checking the app version allows /_ah/admin to work correctly.
I had the same problem due to the fact that I defined a URL filter in my web.xml file:
<filter>
<filter-name>filter</filter-name>
<filter-class>com.example.MyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
The filter class, MyFilter, has a doFilter method as below:
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
String path = req.getRequestURI().substring(req.getContextPath().length());
if (path.equals("/")) { // Welcome path
request.getRequestDispatcher("/res/index").forward(request, response);
} else if (path.startsWith("/static") || path.startsWith("/_ah")) {
// Static content or internal and admin stuff
chain.doFilter(request, response); // Goes to default servlet.
} else { // Jersey servlet controller
request.getRequestDispatcher("/res" + path).forward(request, response);
}
}
The part in the code above reading || path.startsWith("/_ah") solved my problem, because the filter must allow paths starting with /_ah to go through unchanged.
I needed the filter so that Jersey could work without all my REST paths being prepended with /res or whatever is specified in web.xml.
Related
I am messing around with a small go app for google app engine locally using the appengine sdk.
I have a problem where a path different than root can only be served if I try to hit it using localhost, but not a domain name.
My setup is as follows.
home.mydomain.com points to my home ip adress
My home router forwards incoming tcp and udp on port 80 to my laptop on port 8080
My laptop is running Windows 10
My go version is go1.6 windows/amd64
My app.yaml:
application: tasks
version: 1
runtime: go
api_version: go1
handlers:
- url: /.*
script: _go_app
Minimum example code:
func init() {
fileHandler := http.FileServer(http.Dir("../frontend"))
http.HandleFunc("/loggedout", testHandler)
http.Handle("/", fileHandler)
log.Print(http.ListenAndServe(":8080", nil))
}
func testHandler(res http.ResponseWriter, req *http.Request){
panic("JUST NEED THIS TO WORK")
}
My symptoms is that if I access localhost:8080/ I get my website, and if I access localhost:8080/loggedout I get the expected panic.
If I access home.mydomain.com/ I get my website, however if I access home.mydomain.com/loggedout the connection just hangs, in chromes network tab it is listed as pending indefinitely.
As Greg pointed out, when I was using goapp I did not need to also call ListenAndServe.
To get goapp to listen for requests outside of localhost I also had to add --host "my laptops ip" to the command.
I've installed a CakePHP application onto App Engine, and I'm redirecting URLs into it using a wildcard URL in my app.yaml:
url: /.*
script: app/webroot/index.php
The documentation states that /_ah/* URLs will be ignored (I don't know what these are for yet), but they are being caught by my CakePHP app and throwing errors into the error log. I also suspect this is the cause of 500 errors with an appengine error of 204 that keep happening randomly.
Does anyone have a solution for this? How do I ensure that the /_ah/ urls pass through to the app engine and not my specific application code?
Example error:
E 08:51:48.957 2015-03-17 404 841 B 304ms /_ah/start
0.1.0.3 - - [17/Mar/2015:01:51:48 -0700] "GET /_ah/start HTTP/1.1" 404 841 - - "****.appspot.com" ms=304 cpu_ms=416 cpm_usd=0.000094 loading_request=1 instance=0 app_engine_release=1.9.18
E 08:51:48.854 error: [MissingControllerException] Controller class AhController could not be found.
MissingControllerException is thrown by my app.
Request to /_ah/start is an initial request from Appengine itself, to initialize your app. I think you can ignore it, if you don't need to do anything special. Or return empty response.
See docs: https://cloud.google.com/appengine/docs/php/modules/#PHP_Instance_states
I do it in accordance with Custom Error Responses - app.yaml is updated with
error_handlers:
- error_code: over_quota
file: templates/over_quota.html
and according file is created. But still error (exception) is shown instead of that page. I've tried to place the file in the root folder (with according update at app.yaml) - it didn't help.
What am I doing wrong?
Upd. I've defined that in the following way in accordance with #Gwyn Howell comment.
handlers:
- url: /over_quota.html
static_files: templates/over_quota.html
upload: templates/over_quota.html
error_handlers:
- error_code: over_quota
file: over_quota.html
But (1) how to test it, (2) which url user will see in result? http://www.example.com/over_quota.html or will it be original url?
You're going over a specific quota, such as datastore operations, which throws an exception, without going over your instance hours quota. The over quota error message is only shown if App Engine can't send a request to an instance at all due to lack of quota; if the request is sent to your app, but you attempt to do something that exceeds available quota, it's up to you to handle the exception as you see fit.
Has anyone cracked how to get HTTPS working on the dev_appserver.py? I need it for Facebook canvas app testing. I've had a search of the docs and nothing suggests there's a way to do it (sticking 'secure' in the app.yaml doesn't nothing locally).
I was think there may be a way to proxy it, but has anyone got any experience of this?
The dev_appserver doesn't support HTTPS. The only practical way to do this is to set up a reverse proxy in front of your app - such as with nginx or Apache - and have it proxy SSL traffic to your app.
I know this is late, in case anybody else finds this question:
ngrok is quiet easy to setup for a custom reverse HTTPS proxy..
The only downside is that my webapp2 application still believes it's being served over HTTP, so using redirect() doesn't work well because it resolves relative URLs to absolute URLs using request.url.
My workaround was to overwrite RequestHandler.redirect as follows:
class BaseRequestHandler(RequestHandler):
def redirect(self, uri, permanent = False, abort = False, code = None, body = None):
if uri.startswith(('.', '/')):
base_url = self.request.url
if base_url.startswith('http://'):
base_url = 'https://' + base_url[7:]
uri = str(urlparse.urljoin(base_url, uri))
super(RequestHandler, self).redirect(uri, permanent, abort, code, body)
I needed a BaseRequestHandler class anyways for implementing other utility functions.
I put this in my Appache httpd.conf to proxy the connection:
<Location /myproject/>
ProxyPass http://localhost:8080/
</Location>
Now going to https://localhost/myproject/ in my browser worked.
Note: SSL needs to be enabled on your Apache server. On my OS X machine I uncommented out the line Include /private/etc/apache2/extra/httpd-ssl.conf in /etc/apache2/httpd.conf and ran sudo apachectl restart
I'm getting this error from a request called from the task queue. It suggests I need to change the app.yaml handler but I think I have the correct handler
Here is the error log entry:
2011-11-17 13:30:35.849 /tasks/kacher 302 209ms 0kb
0.1.0.1 - - [17/Nov/2011:13:30:35 -0800] "GET /tasks/kacher HTTP/1.1" 302 0 - - "rawload.XXX.appspot.com" ms=209 cpu_ms=0 api_cpu_ms=0 cpm_usd=0.000032 queue_name=default task_name=cf2e2f1d39d108b3972a1da8c6532fea
W2011-11-17 13:30:35.842
Request failed because URL requires user login. For requests invoked within App Engine (offline requests like Task Queue, or webhooks like XMPP and Incoming Mail), the URL must require admin login (or no login).
This is the code to call the task:
taskqueue.add(url='/tasks/kacher',target='rawload',method='GET')
Here is my app.yaml, with the task urls as login:admin which seems correct (to me):
- url: /tasks.*
script: main.py
login: admin
- url: .*
script: main.py
login: required
secure: always
There's a known bug in the dev_appserver with tasks that require admin login sometimes failing like this. Try logging your browser session in as an admin before accessing the URL that enqueues the task, or try uploading your app to production to see if you experience the issue there.