I'm trying google app engine with python27.
handlers:
- url: /favicon\.ico
static_files: favicon.ico
upload: favicon\.ico
- url: /hello
script: helloworld.app
- url: /.*
script: main.app
helloworld.py and main.app have the same code from the offical document with little difference (response string).
import webapp2
class MainHandler(webapp2.RequestHandler):
def get(self):
self.response.write('Hello world!!!')
app = webapp2.WSGIApplication([
('/', MainHandler)
], debug=True)
My result:
1. "~", the response comes from "main.app".
2. "~/favicon.ico", the response comes from "favicon.ico".
3. "~/hello", the response is "404".
4. "~/something", the response is "404".
Sorry, to post this question, "~" for "http://localhost:8080".
Why 3 and 4 cannot be handled? Is there something wrong?
Try changing ('/', MainHandler) to (r'/.*', MainHandler) (the r just indicates it is a raw string). The problem is that you don't currently have any handlers for anything other than your root /, so requests with other parameters (such as http://localhost:8080/hello) have no matching handler and therefore it is unknown how to handle it. Changing the handler to /.* means that all requests (regardless of what comes after the root) should be routed to your MainHandler.
As for the app.yaml handlers and the handlers in your *.py file, think of the app.yaml as the high-level director. It gets a request and simply determines where to send it (am I getting a request for a static Javascript file? CSS? Picture? Or is this a request that should serve a page, etc.?). In the case such as yours above, you want it to serve a particular page when hitting any URL that is not /favicon (so /.*), so what it does is takes any request to /.* and routes it to main.app, which is in your main.py file (I'm ignoring helloworld.app for now, mainly because in your situation you don't necessarily need it).
It is then that the more granular handling happens - main.app receives the original request, and then it looks for a specific handler to execute the code. When we change your handlers to r'/.*', it matches anything that comes in (so /, /hello, /helloworld, etc.), and it executes the corresponding class MainHandler, in this case).
Related
I'm running a static site on GAE and using a custom domain (let's call it example.com) with SSL certificates enabled. I'd like to canonicalize URLs to https://www.example.com/. That means catching any requests to myproject.appspot.com, plain HTTP, and/or the naked domain, and redirecting to www over HTTPS.
I understand that it's not possible to put redirect logic in app.yaml, but ideally I'd like to keep the static file serving logic there, and only have app code for the redirect. (As opposed to doing the static serving in app code as well.)
Here's what I have so far:
Contents of the file app.yaml:
runtime: python27
api_version: 1
threadsafe: true
handlers:
- url: /
static_files: www/index.html
upload: www/index.html
- url: /(.*)
static_files: www/\1
upload: www/(.*)
Contents of the file dispatch.yaml:
dispatch:
- url: "myproject.appspot.com/*"
module: canonicalizer
Contents of the file canonicalizer.yaml:
module: canonicalizer
runtime: python27
api_version: 1
threadsafe: true
handlers:
- url: /.*
script: canonicalizer.app
Contents of the file canonicalizer.py:
import webapp2
def get_redirect_uri(handler, *args, **kwargs):
return 'https://www.example.com/' + kwargs.get('path')
app = webapp2.WSGIApplication([
webapp2.Route('/<path:.*>',
webapp2.RedirectHandler,
defaults={'_uri': get_redirect_uri, '_code': 302}),
], debug=True)
As you can see, I've only attempted to implement redirecting myproject.appspot.com so far. I haven't been able to get it working; myproject.appspot.com still serves content rather than redirecting to the custom domain.
I saw a similar SO question and used it as a basis for my code above. I followed it fairly closely, so I'm not sure if it's outdated or missing details.
I'm not very familiar with webapp2. Also open to solutions in a different framework or even different programming language.
As sllopis said in their answer, an HTTP to HTTPS redirect can be implemented via a secure: always element.
The rest of what I wanted to do needed to be done in app code. The code in my answer was on the right track, but I had some confusion about how services work in GAE and about dispatch.yaml. Here's my final code:
<application root>/app.yaml
runtime: python27
api_version: 1
threadsafe: true
handlers:
- url: /
static_files: www/index.html
upload: www/index.html
secure: always
redirect_http_response_code: 301
- url: /(.*)
static_files: www/\1
upload: www/(.*)
secure: always
redirect_http_response_code: 301
<application root>/dispatch.yaml
dispatch:
- url: "*.appspot.com/*"
service: canonicalizer
- url: "example.com/*"
service: canonicalizer
<application root>/canonicalizer/app.yaml
service: canonicalizer
runtime: python27
api_version: 1
threadsafe: true
handlers:
- url: /.*
script: canonicalizer.app
<application root>/canonicalizer/canonicalizer.py
import webapp2
def get_redirect_uri(handler, *args, **kwargs):
return 'https://www.justinforcentral.com/' + kwargs.get('path')
app = webapp2.WSGIApplication([
webapp2.Route('/<path:.*>',
webapp2.RedirectHandler,
defaults={'_uri': get_redirect_uri, '_code': 301}),
], debug=False)
This allows all the redirects to be done while still maintaining the ability to route the static site via static_files handlers.
As an aside, I also didn't realize that simply doing gcloud app deploy . from the application root only deploys the default service. To deploy this whole thing I had to run gcloud app deploy . dispatch.yaml canonicalizer.
Mapping Custom Domains to GAE
App Engine allows applications to be served via a custom domain, such as example.com, instead of the default appspot.com address. You can create a domain mapping for your App Engine app so that it uses a custom domain.
You will need to do the following:
Verify that you are the owner of your domain through Webmaster Central
Ensure that your domain has been verified.
Delegate the ownership of your domain to other users or service accounts, if needed.
Map your domain to your App Engine app.
Fill out the form with the listed resource records, including their type and canonical name (CNAME).
Add this information to the DNS configuration of your domain registrar.
Securing Custom Domains with SSL
By default, when you map your custom domain to your app, App Engine issues a managed certificate for SSL for HTTPS connections. Securing your custom domains with SSL offers more information about this.
Handling URL requests that do not use HTTPS
Any URL handler can use the secure setting, including script handlers and static file handlers. If secure is set to always, requests for a URL that match this handler that do not use HTTPS are automatically redirected to the HTTPS URL with the same path. Query parameters are preserved for the redirect.
Example in the app.yaml file:
handlers:
- url: /youraccount/.*
secure: always
script: auto
Conclusion
As a result, after following these steps, you should have a custom domain properly mapped to your App Engine site that uses SSL certificates to secure the custom domain.
Moreover, by adding the secure:always handler in your app.yaml file, any URL requests made against your App Engine site will be automatically redirected to the HTTPS URL with the same path.
Update - Redirect all URLs with Google App Engine
Credits to How to redirect all URLs with Google App Engine:
app.yaml
handlers:
- url: /.*
script: main.py
main.py
import webapp2
class MainPage(webapp2.RequestHandler):
def get(self):
self.redirect("https://example.com", True)
app = webapp2.WSGIApplication([
('/', MainPage),
], debug=True)
Then, you can adjust this code to your needs.
My application contains Angular and Php Yii2 framework.
I hosted my application on Google App Engine.
Here is the contents of my app.yaml file:
threadsafe: true
runtime: php55
api_version: 2
handlers:
# The root URL (/) is handled by the Go application.
# No other URLs match this pattern.
- url: /(.+)
static_files: \1
upload: (.*)
- url: /web-service/*
script: web-service/yii
- url: /
static_files: index.html
upload: index.html
My Yii2 library is available in web-service directory, but when I call REST API from the postman, it then returns a '404 page not found' error.
Am I missing something in my app.yaml file?
Please help me solve this issue. My API call is something like this:
https://abcxyz.appspot.com/web-service/web/user-registration/login-user
Several problems:
api_version: 2 - there is no such version presently, set it to 1. From the api_version row in the Syntax table:
At this time, App Engine has one version of the php runtime
environment: 1
the order of the handlers in app.yaml matters, the first one with a matching pattern will be used. Your url: /(.+) pattern will match all of your /web-service/* requests as well, so static files uploads will be attempted instead of the script(s) you're expecting. Re-order your handlers with the most significant patterns preceeding the less significant ones.
your script: web-service/yii entry might not be OK if other php files need to be served from the web-service dir (the web-service/yii will always be the one served, regardless of the requested script). Instead I'd use the handler suggested in the Example (assuming the script names always end with .php):
# Serve php scripts.
- url: /(.+\.php)$
script: \1
Always check the request entries in the development server logs as a starting point to debug request failures.
I am following the Quickstart for Cloud Endpoints Frameworks on App Engine in standard environment. I have deployed the sample API. When I open https://[my-project].appspot.com/ I get the error message:
Error: Not Found. The Requested URL / was not found on this server
The logs show the message:
No Handlers matched this url
The app.yaml handlers are the what came with the endpoints-frameworks-v2/echo sample:
handlers:
# The endpoints handler must be mapped to /_ah/api.
- url: /_ah/api/.*
script: main.api
I was having great difficulty generating the OpenAPI configuration file in a previous step of the quickstart. I got it to work by updating the system variable path for the SDK but I did get this error:
No handlers could be found for logger "endpoints.apiserving"
WARNING:root:Method echo.echo_path_parameter specifies path parameters buy you are
not using a ResourceContainer. This will fail in future releases; please
switch to using ResourceContainer as soon as possible.
I have no idea if this error is relavant to the current problem.
Any help would be much appreciated.
Regarding the "No handlers could be found for logger..." you need to do this:
http://excid3.com/blog/no-handlers-could-be-found-for-logger
The other issue is a known issue:
What are ResourceContainers and how to use them for Cloud Endpoints?
You need a url handler for / if that is a valid url:
handlers:
# The endpoints handler must be mapped to /_ah/api.
- url: /_ah/api/.*
script: main.api
- url: /.* # catchall for all other urls
script: main.api # or wherever you handle the request for `/` and others
I tried to use the documented way of restricting access to urls marked as static by way of login: required rules in the app.yaml file. My intention is to have access to script urls handled by the go programming language by xmlhttprequests, but the first step of authenticating the user before she can load the file dist/index.html fails.
Surprisingly for me the user is not prompted to login, instead receives the dist/index.html file and all other files it asks for from the static folder as if no restricting rule were present.
This is my app.yaml file:
application: helloworld
version: 1
runtime: go
api_version: go1
handlers:
- url: /
static_files: dist/index.html
upload: dist/index.html
secure: always
login: required - this is what fails as far as I'm concerned
- url: /(.*\.(txt|html|json|png|js|log|md|css|ico))
static_files: dist/\1
upload: dist/(.*\.(txt|html|json|png|js|log|md|css|ico))
secure: always
login: required
- url: /.*
script: _go_app
secure: always
login: required
The folder that I uploaded to appengine looks like this:
app.yaml
index.yaml
xhr_responses.go - this is the intended future non static AJAX part
dist/
index.html
loads of other stuff that is static
The 'login:' handler options in the .yaml config files rely on Google's authentication, which can be persisted using cookies and survive a browser restart.
To properly test the authentication you need to either use a fresh incognito browser session or go to one of the Google sites and ensure you're not logged in (explicitly log out from all Google accounts if needed) before testing.
Apparently I was signed in when trying stuff on the live google app engine, which I just forgot is the way it knows not to redirect access to a new login prompt.
I would like to know if is there a way to validate that a request (say a POST or a GET) was made over https,
I need to check this in a webapp2.RequestHandler to invalidate every request that is not sent via https
best regards
Check the self.request.environ['HTTPS'] == 'on' # or 'off'.
If you only use https, consider using secure:always in your app.yaml as follows:
handlers:
- url: /.*
script: main.app
secure: always
The answer provided above to use the app.yaml config works well but in some case you need the granularity of checking this your python code itself, which is I believe what you asked for since you want to check in the RequestHandler.
Here is what you can do inside your RequestHandler:
if self.request.scheme.lower() != 'https':
self.abort(403)
else:
# handle your request here, you know it's secured!
If you are using GAE Flex (where the secure: directive doesn't work), the only way I've found to detect this (to redirect http->https myself) is to check if request.environ['HTTP_X_FORWARDED_PROTO'] == 'https'