Getting Flask to use the desired URL behind mod-rewrite - .htaccess

I have a Flask app running under mod_wsgi on Apache. Due to various parts of the website being static and others being dynamic, the dynamic parts of the website are routed to the Flask app using mod_rewrite as shown below:
.htaccess
RewriteEngine on
RewriteBase /
RewriteRule ^(foo(/.*)?)$ /myapp.wsgi/$1 [L,QSA]
RewriteRule ^(bar(/.*)?)$ /myapp.wsgi/$1 [L,QSA]
# etc.
myapp.wsgi
from flask import Flask, request
application = Flask(__name__)
#application.route("/foo/")
def foo():
return request.url
#application.route("/bar/")
def bar():
return redirect(request.url + "baz/")
When I visit http://www.mywebsite.com/foo/ the page tells me that my URL is http://www.mywebsite.com/myapp.wsgi/foo/.
When I visit http://www.mywebsite.com/bar/ the page redirects me to http://www.mywebsite.com/myapp.wsgi/bar/baz/.
This also happens with Flask's automatic redirects: when I visit http://www.mywebsite.com/foo (no trailing slash), Flask redirects to add the slash, but it redirects to http://www.mywebsite.com/myapp.wsgi/foo/.
Is there an easy way to get the Flask app to not include the /myapp.wsgi in the URLs and instead use just use URLs relative to where the routes are? (e.g. /foo/ and /bar/)

This can be solved by removing the name of the script from the SCRIPT_NAME environment variable using some middleware as in the below example taken from the Flask docs.
from yourapplication import app
class ScriptNameStripper(object):
def __init__(self, app):
self.app = app
def __call__(self, environ, start_response):
environ['SCRIPT_NAME'] = ''
return self.app(environ, start_response)
app = ScriptNameStripper(app)

I don't know if I understood well but you might want to use url_for function documented here :
http://flask.pocoo.org/docs/0.10/api/#flask.url_for
It allows you to construct URLs by referencing endpoints of you application.
For example url_for('bar') would construct the relative URL pointing the bar endpoint.

Related

Robots.txt returns 404 instead of displaying text

Problem
When trying to request my robots.txt file at website.com/robots.txt, I always receive a 404 error.
Files
config > urls.py
from django.conf import settings
from django.contrib import admin
from django.urls import path, include, re_path
from django.views.generic import TemplateView
from django.conf.urls.static import static
from config import views
from django.conf.urls import handler404, handler500, handler403, handler400
handler404 = views.handler404
handler500 = views.handler500
urlpatterns = [
path('admin/', admin.site.urls),
path('accounts/', include('allauth.urls')),
path('accounts/', include('django.contrib.auth.urls')),
path('', include('pages.urls')),
path('plants/', include('plants.urls')),
path('robots.txt',TemplateView.as_view(template_name='robots.txt', content_type='text/plain')),
]
config > views.py
from django.http import JsonResponse, Http404, HttpResponse
from django.shortcuts import render
def handler404(request, exception=None):
return render(request, '404.html', status=404)
def handler500(request):
return render(request, '500.html', status=500)
templates > robots.txt
User-Agent: *
Disallow: /admin/
Disallow: /accounts/
Parts of my folder structure that may be helpful to know
project
|
|---config
| |
| |---urls.py
| |---views.py
|
|---templates
|
|---pages
| |---about.html
| |---contact.html
|
|---404.html
|---robots.txt
I've also tried using only exception instead of exception=None inside of my handler404.
I've tried to move the robots.txt views and urls into my pages app with the robots.txt within the pages template folder.
I've tried removing the content_type=text/plain from the url pattern.
I've read through several different tutorials and I'm not sure what I'm doing wrong.
Some of your secondary urls.py files contain too general pattern which catches "robots.txt" thus URL dispatcher never reaches expected pattern declaration in the end of pattern list.
To fix the issue try moving robots pattern higher in the pattern list and/or review included urls.py files and make their patterns more specific.
Also please consider making "static" robots.txt file truly STATIC in terms of Django. Such files are not supposed to be served by Django backend on prod and do not need template engine involved.

adding a favicon to flask

I'm trying to follow the instructions given here: Adding a favicon to a Flask server without HTML on how to add a favicon to a flask app, however its not working for me. Here is my application file:
from flask import Flask,send_from_directory
application=Flask(__name__)
#application.route('/')
def main():
return '<html><p>hello world</p></html>'
#application.route('/favicon.ico')
def favicon():
return send_from_directory(os.path.join(application.root_path, 'static'),
'favicon.ico',mimetype='image/vnd.microsoft.icon')
if __name__=='__main__': application.run(debug = True)
and here is my directory structure:
➜ demo ls -R
application.py static
./static:
favicon.ico
When I run the application in Firefox, no favicon is shown, and when I run it in Chrome, the default favicon is shown. I used this website to convert a png into an ico file:
https://www.freeconvert.com/png-to-ico
Please let me know where I'm going wrong.
When I run the app in chrome, I get this error in the console:
GET http://localhost:5000/favicon.ico 500 (INTERNAL SERVER ERROR)
I needed to import os, here is the working application:
from flask import Flask,send_from_directory
import os
application=Flask(__name__)
#application.route('/')
def main():
return '<html><p>hello world</p></html>'
#application.route('/favicon.ico')
def favicon():
return send_from_directory(os.path.join(application.root_path, 'static'),
'favicon.ico',mimetype='image/vnd.microsoft.icon')
if __name__=='__main__': application.run(debug = True)

Page not found "/" route

I'm trying to setup a VueJS app using Nuxt for server side rendering. However after deployment to my server the index.vue is return a 404 Page not found error.
This doesn't happen when run on my development machine, and still happens even if run in Development mode on my server.
All other routes work, and getting to the index route from within the app itself works fine. It just doesn't load when refreshed. Eg:
http://myapp.com/ Doesn't work
http://myapp.com/login Works fine
My pages folder currently looks like this:
- pages
-- index.vue
-- login.vue
I have nothing fancy set up within my nuxt.config file and have pretty much the same setup as is described in the Auth0 example
On my server I'm running nuxt with the command pm2 start npm --name "my-app" -- start Which runs fine without any errors, and I have the following .htaccess config:
RewriteCond %{HTTP_HOST} ^my-app\.com$ [OR]
RewriteRule ^(.*) "http\:\/\/127\.0\.0\.1\:3000\/$1" [P,L]
This is the error screen I get:
The page itself is very basic at the moment, it did have far more on it however I've cut it down to the following trying to debug this issue:
<template>
<v-container grid-list-md>
<v-layout row wrap>
<h1>Test index, trying to fix the 404</h1>
<h2>Hello, {{ loggedUser ? loggedUser : 'friend' }}!</h2>
</v-layout>
</v-container>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
computed: mapGetters([
'isAuthenticated',
'loggedUser'
])
}
</script>
I seem to have managed to fix this. However, I'm not completely sure on the cause the fix involved modifying my .htaccess. I started playing with the settings and ended up with the following which works well (for now at least).
RewriteCond %{HTTP_HOST} ^my-app\.com$
RewriteRule "(.*\.(jpg|gif|png|svg|js|css))$" "http://127.0.0.1:3000/$1" [P,NC]
RewriteRule ^(.*) "http\:\/\/127\.0\.0\.1\:3000\/$2" [P,L]
The rule for jpg|gif etc is required as they don't load when using the second rule.

Get project base url that works in XAMPP and on production, considering .htaccess

I have a project that is not in the root of the XAMPP folder:
htdocs/my-folder/projects/my-project
htdocs/my-folder/projects/my-project/index.php
htdocs/my-folder/projects/my-project/js/
htdocs/my-folder/projects/my-project/css/
that folder contains an index.php file from where I try to call stylesheets and scripts. Initially, I'd just do it like this:
<script src="js/myscript.js"></script>
which worked. However, the project has expanded and now a user can "save" the current page (similar to how JSFiddle does it), and the URL will look different. Upon a first save a random string will be appended as a conf parameter, which results in something like this (locally) and should have a public equivalent:
localhost/my-folder/projects/my-project?conf=abcd # locally
http://mywebsite.com/projects/my-project?conf=abcd # publicly
Upon second save, the URL gets an additional parameters, a version number:
localhost/my-folder/projects/my-project?conf=abcd&v=2 # locally
http://mywebsite.com/projects/my-project?conf=abcd&v=2 # publicly
But, to get a nice URL I use this .htaccess:
Options +FollowSymLinks -MultiViews
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (\w+)[/](\d+)$ ?conf=$1&v=$2 [L,NC]
which will result in something like this:
localhost/my-folder/projects/my-project/abcd/2 # locally
http://mywebsite.com/projects/my-project/abcd/2 # publicly
The thing is, when the URL is changed to some structure as above (without the parameters, but with the rewritten URLs, e.g. localhost/my-folder/projects/my-project/abcd/2) then the initial call to the resources (scripts, styles) in my index file won't be correct any longer.
In other words, if this is the url: localhost/my-folder/projects/my-project/abcd/2 then the server will look for a a script file in localhost/my-folder/projects/my-project/abcd/2/js/myscript.js, which is obviously wrong.
The question, thus, is: how can I get the absolute path to the current file, but that also works in XAMPP (so not __FILE__ or __DIR__ which will dig in the file strucure and return file://) and also on production environments.
You'll have to use the base element in your pages. The usage will be something like:
<base href="/projects/my-project/" />
for the public server and
<base href="/my-folder/projects/my-project/" />
locally.
I hackingly figured it out. By checking the end of the url, we determine if we are in root or if we are in a specific instance (ending with a digit e.g. /1.
<?php
// Is connection secure? Do we need https or http?
// See http://stackoverflow.com/a/16076965/1150683
$isSecure = false;
if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
$isSecure = true;
} elseif (!empty($_SERVER['HTTP_X_FORWARDED_PROTO'])
&& $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https'
|| !empty($_SERVER['HTTP_X_FORWARDED_SSL'])
&& $_SERVER['HTTP_X_FORWARDED_SSL'] == 'on') {
$isSecure = true;
}
$REQUEST_PROTOCOL = $isSecure ? 'https' : 'http';
$REQUEST_PROTOCOL .= '://';
// Create path variable to the root of this project
$path_var = $REQUEST_PROTOCOL.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
// If URL ends in a slash followed by one or more digits (e.g. http://domain.com/abcde/1),
// returns a cleaned version of the URL, e.g. http://domain.com/
if (preg_match("/\/\d+\/?$/", $path_var)) {
$path_var = preg_replace("/\w+\/\d+\/?$/", '', $path_var);
}
?>
Now we can use it in our PHP file!
<link href="<?php echo $path_var; ?>css/styles.css" rel="stylesheet">

Confused about path settings with Tornado server

I'm using bower to grab the .css and .js files for my website.
The directory structure looks like this:
server.py
bower_components/
templates/
All of the HTML templates (and some partials templates that I use with AngularJS) are located in templates. Stuff installed by bower is located in bower_components. How can I define template_path, static_path and static_url_prefix settings so that I can link into files in those directories?
If I use relative paths like:
href="bower_components/bootstrap/dist/css/bootstrap.css"
I will get 404 error. No handlers can be found so the error is thrown. It seems that Tornado forces me to use static_url function on my templates? Do I really have to use it? It looks very ugly when mixed with AngularJS. I have tried setting static_path to os.path.dirname(file) and tried using static_url but that gives me exception:
Exception: You must define the 'static_path' setting in your application to use static_url
How should I configure this? I can't believe I have wasted hours trying to figure this out already... :(
Did you try to use the StaticFileHandler? You can use something like this:
import os
import tornado.web
import tornado.ioloop
if __name__ == '__main__':
app = tornado.web.Application([
(r"/(.*)", tornado.web.StaticFileHandler, {"path": os.path.dirname(os.path.abspath(__file__))}),
])
app.listen(8888)
tornado.ioloop.IOLoop.instance().start()
You must combine staticfilehandler with some path variables you put in the settings variable.
http://tornado.readthedocs.org/en/latest/web.html
It's pretty easy. You can name as many settings variables as you want.
It turned out I needed to use tornado.web.StaticFileHandler class with path mapped to it. This is how I configured my tornado.web.Application:
class TornadoApp(tornado.web.Application):
def __init__(self):
# static file regex patterns matched with the actual folders here
static_handlers = {
'/bower_components/(.*)': 'bower_components',
'/templates/partials/(.*)': 'templates/partials'
}
handlers = [
('/', IndexHandler),
('/products', ProductHandler),
]
# append the handlers with content from static_handlers dictionary
for r, p in static_handlers.items():
handlers.append((r, tornado.web.StaticFileHandler, {'path': p}))
settings = {
'template_path': "templates",
'debug': True
}
tornado.web.Application.__init__(self, handlers, **settings)

Resources