0

I'm trying to develop a small music app using Flask and Docker. I have two docker services in my compose, both running Flask.

The first one is called uploader:

@app.route("/get_song/<string:filename>/", methods=["GET"])
def get_song(filename):
    path = os.path.join(flask.current_app.instance_path, flask.current_app.config["UPLOAD_FOLDER"])
    return flask.send_from_directory(path, filename, as_attachment=True)

The second one renders a Jinja template which attempts to play the file returned by this API:

<audio controls="controls" autoplay="autoplay"></audio>

<a href="javascript:void(0);" onclick="playSong('{{song}}')">{{song}}</a>`

<script type="text/javascript">
    function playSong(song){
        $('audio').attr('src', 'http://uploader:5000/get_song/'+song);
    }
</script>

Separately, these components work just fine. But when used together, the file doesn't play. I've tried pretty much everything I found online and nothing seems to work. Any help would be extremely appreciated. Thanks!

Edit: Added docker-compose file. Both docker images are built locally.

version: "3"
services:
  uploader:
    image: project_uploader:latest
    ports:
      - "4000:5000"
    networks:
      - upload
  frontend_server:
    image: project_frontend_server:latest
    ports:
      - "5000:5000"
    networks:
      - upload

networks:
  upload:

1 Answers1

1

The HTML fragment you show is ultimately executed in the browser; but the browser runs outside of Docker space and isn't aware of the Docker-internal host names.

<!-- browser doesn't know about a host named "uploader" -->
<audio src="http://uploader:5000/get_song/..." />

When you create this HTML fragment, you need to provide the name of the host the server is running on and the published ports: number of the other container. If the browser and containers are running on the same system (and it's not using Docker Toolbox) you can use localhost as the host name.

$('audio').attr('src', 'http://localhost:4000/get_song/'+song);

Probably the most robust way to handle this is to set up a reverse proxy like Nginx. Browser applications would point at the proxy, and it would forward things to one container or the other. If you can do this, then you can use a path-only URL and let the host name be the same as the main page.

$('audio').attr('src', '/uploader/get_song/'+song);
David Maze
  • 130,717
  • 29
  • 175
  • 215
  • Wow, that worked like a charm! I didn't think of that, most of the API calls are executed using the docker-internal host names. But it makes sense, the browser does not know about them. Thank you so much! – Alin Tache May 06 '20 at 12:39