javascriptpythonajaxxmlweb.py

XMLHttpRequest Returns 404 Even Though File Exists


This is what the file structure for my project looks like. Voice, Text and Template are folders.

Folder structure for my project: "Voice" folder contains app.py file and folders Text and Template. Text contains voice.txt, and Template contains index.html

I run python app.py, and when I go to localhost http://0.0.0.0:8080/ I can see the index.html page with content piped in by app.py.

There's text in index.html that's piped in from voice.txt, and if I view voice.txt in my text editor I can see that a loop in app.py is successfully appending more text to it every 20 seconds.

The issue I'm having is trying to get the updated voice.txt text into the body of index.html. I'm trying to do this with XMLHttpRequest. Here's the relevant code from the tag in index.html:

function UpdateText() {
var xhttp = new XMLHttpRequest();

xhttp.onreadystatechange = function(){
    if (this.readyState == 4 && this.status == 200) {
        // Code goes here
        document.getElementById("main").innerHTML = this.responseText;
        console.log(statusText);
        console.log(responseText);
    }
};

xhttp.open("GET", "../Text/voice.txt", true);
xhttp.send();

};

When I run that index.html displays properly, but when it tries to update the text I get the following error message in Terminal:

127.0.0.1:64013 - - [28/May/2019 00:55:10] "HTTP/1.1 GET /Text/voice.txt" - 404 Not Found

I could be wrong but at this point I'm fairly sure that the filepath in xhttp.open() should actually be a URL (this is the first time I'm using XMLHttpRequest and every tutorial I've seen just has the filename and nothing else), in which case I'm not sure how I'd link to voice.txt. I'm using the web.py library for this, here's the relevant section of app.py:

urls = (
"/", "index",
)

indexpath = "/Users/[USERNAME]/torch/torch-rnn/voice/Template/"
render = web.template.render(indexpath)

class index(object):
def GET(self):
    the_voice = open(voicepath, "r+").read()    
    return render.index(the_voice)

if __name__ == "__main__":
app = web.application(urls, globals())
app.run()

I feel like the solution probably involves changing something in either the urls or render variables, but I've been going around in circles with this for hours and I'm out of ideas.

What I've Tried

First thought I had was to throw a dummy file called also called voice.txt into the Template folder next to index.html then change the filepath in the XMLHttpRequest to reflect that, but I still got the same error message.


Solution

  • Your web server only knows about a single URL "/" and will return it when asked as 'https://:8080/'. That's all you've listed as possible values in your urls =() bit.

    So, your attempt to get, via web interface, anything else will fail. If you want to have the webserver retrieve your voice.txt file, you need to include it, or something which will match it, in urls, and have that class then get and send on the voice.txt file. (Note that files themselves aren't in a Text folder, they could be anywhere, as described by myDirectory.)

    For example,

    urls = ( "/", "index",
             "/Text/(.*)", "get_file")
    
    class get_file(object):
        def GET(self, filename):
            the_file = open(myDirectory + '/' + filename, "r").read()
            return the_file
    

    might do what you want (or give you some ideas). By using the regular expression in urls, any http get like '/Text/foo', '/Text/voice.txt', '/Text/ant_eater.jpg' will attempt to read the file ('foo', 'voice.txt', 'ant_eater.jpg') in the directory described by myDirectory, and return that file to the user.

    If you're serving different types of files (as with my example) you should also set headers for the content type, but that's a different question.