Search code examples
pythonflaskhttpserver

How to serve Flask With Http Server


I would like to develop an app that uses both Flask and httpd. Flask publishes HTML-related files, and httpd publishes files in local files.

It is for browsing local files published in httpd from Flask HTML.

Though the port numbers of Flask and httpd are different, it seems that httpd server side is not working. Connection refused error occurs when connecting to httpd server.


Added the intention of the question.

I want to run Flask's built-in web server and HTTPServer simultaneously from a script. I just want to be able to see myself, not to expose it to the network.

I'm looking for a mechanism that can be completed with the app.py script without using WSGI.


Added additional information to the question.

This question uses Flask and Python's HTTPServer, but using NodeJS's HTTPServer instead of HTTPServer seems to work well. (Comment out run())

I would like to complete in Python if possible without using NodeJS HTTPServer.

https://www.npmjs.com/package/http-server

C:\Users\User\Videos>http-server
Starting up http-server, serving ./
Available on:
  http://127.0.0.1:8080
Hit CTRL-C to stop the server
...

version

Flask==1.0.2
Python 3.7

Can I not start each server with the following code?

templates/index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title></title>
</head>
<body>
  <video src="http://localhost:8080/video.mp4"></video>
</body>
</html>

python(app.py)

from http.server import SimpleHTTPRequestHandler, HTTPServer

from flask import Flask, render_template

app = Flask(__name__)


@app.route('/')
def hello_world():
    return render_template('index.html')


class Handler(SimpleHTTPRequestHandler):
    def __init__(self, *args, directory=None, **kwargs):
        super().__init__(*args,
                         directory=r'C:\Users\User\Videos',
                         **kwargs)


def run(server_class=HTTPServer, handler_class=Handler):
    server_address = ('localhost', 8000)
    httpd = server_class(server_address, handler_class)
    httpd.serve_forever()


if __name__ == '__main__':
    app.run(host='localhost', port=5000)
    run()

It may not have been transmitted well. I'm sorry.
Thank you very much.


Solution

  • Can I not start each server with the following code?

    Yes, there are many other ways.

    WSGI

    wsgi, which stands for Web Server Gateway Interface is defined in PEP 333:

    This document specifies a proposed standard interface between web servers and Python web applications or frameworks, to promote web application portability across a variety of web servers.

    framework side

    flask, django and many other frameworks all implement this interface. So when you write an app in flask, app implements wsgi so any web server that knows how to serve a wsgi app can serve it.

    web server side

    There are many choices and you can find more at wsgi.org:

    Basically, you can choose any of these to start your server and use httpd to proxy requests to it. Or you can use mod_wsgi:

    mod_wsgi is an Apache module that embeds a Python application within the server and allow them to communicate through the Python WSGI interface as defined in the Python PEP 333.

    Note

    The bundled server in flask is not suitable for production use, you can see this question for more details.


    For Updated Question

    I want to run Flask's built-in web server and HTTPServer simultaneously from a script.

    Just Run Shell Command

    You can start another process and call shell command using Popen:

    if __name__ == '__main__':
        p = Popen(['python -m http.server'], shell=True)
        app.run(host='localhost', port=5000)
    

    Use whatever command you like, you can even start a node http server here.

    Use Thread/Process

    You can start http server in another thread or process, here I use threading for example:

    if __name__ == '__main__':
        from threading import Thread
        Thread(target=run, daemon=True).start() 
        app.run(host='localhost', port=5000)
    

    Use Flask To Serve File

    Instead of starting two servers binding to two ports, you can actually use flask to serve file as well. In this way, you only start one server binding to one port:

    @app.route('/videos/<path:filename>')
    def download_file(filename):
        return send_from_directory(r'C:\Users\User\Videos',
                                   filename, as_attachment=True)
    

    You can see documentation for more details.