“WARNING:tornado.access:405” error stopping POST f

2019-07-31 23:21发布

问题:

This is a very similar problem to this question (Tornado POST 405: Method Not Allowed), but the dead simple answer for that question is still not working. There are also many, many more similar questions in the side bar -----> which are not related to Tornado, and did not provide me with a solution.

Right now I am using Firefox on OSX.

My tornado code is as follows:

import tornado.ioloop
import tornado.web

class MainHandler(tornado.web.RequestHandler):
    def post(self):
        self.write("Hello, world")
    get = post # <--------------

application = tornado.web.Application([
    (r"/", MainHandler),
])

if __name__ == "__main__":
    application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

If I run GET, it works fine, but if I use POST, I get the error on client side HTTP/1.1 405 Method Not Allowed and the error on server side WARNING:tornado.access:405 OPTIONS. I have tried running the js in both a file://index.html and localhost:8000/index.html setting

My test js looks like this:

//this one returns the error
U.Ajax.post("http://localhost:8888/", "text", "data = fez hat")
.then(function(result) {
    console.log(result);
});

//this one works
U.Ajax.get("http://localhost:8888/", "text", "data = fez hat")
.then(function(result) {
    console.log(result);
});

My ajax code looks like this, if that's any help:

//tested and functional ajax code, for ease of testing
U = {};
U.Ajax = {};
U.Ajax.send = function(getOrPost, url, dataType, data) {
    return new Promise( function(resolve, reject) {
        var request = new XMLHttpRequest();

        if(getOrPost == "GET") {
            request.responseType = dataType || "text";
            request.open("GET", url);   
        }
        else {//getOrPost == "POST"
            request.open("POST", url);  
            request.setRequestHeader('Content-type', dataType)
        }


        request.onload = function() {
            if (request.status >= 200 && request.status < 400) {
                console.log("ajax", request.status+" "+url, request);

                resolve(request);               

            } else {
                request.onerror();
            }
        };

        request.onerror = function() {
            var err = "include src '"+url+"' does not exist";
            console.log(err)
            reject(err)
        };

        try {
            request.send(data); 
        }
        catch(e) {
            var err = "NS_ERROR_DOM_BAD_URI: Access to restricted URI '"+url+"' denied";
            console.log(err)
            reject(err)
        }


    });
}

U.Ajax.get = function(url, responseType) {
    return U.Ajax.send("GET", url, responseType);
}

U.Ajax.post = function(url, contentType, data) {
    return U.Ajax.send("POST", url, contentType, data);
}

EDIT :: If I change the tornado code to equate GET POST and OPTION, it works, but incorrectly

class MainHandler(tornado.web.RequestHandler):
    def post(self):
        print(self.request)
    get = options = post # <--------------

I no longer get an error, but when I print self.request it appears that my headers are set to "OPTIONS" somehow

HTTPServerRequest(protocol='http', host='localhost:8888', method='OPTIONS', uri='/', version='HTTP/1.1', remote_ip='127.0.0.1', headers={'Origin': 'null', 'Accept-Language': 'en-US,en;q=0.5', 'Accept-Encoding': 'gzip, deflate', 'Access-Control-Request-Headers': 'content-type', 'Host': 'localhost:8888', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8', 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.11; rv:55.0) Gecko/20100101 Firefox/55.0', 'Access-Control-Request-Method': 'POST', 'Connection': 'keep-alive'})

回答1:

I no longer get an error, but when I print self.request it appears that my headers are set to "OPTIONS" somehow

That would be the CORS pre-flight request.

https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request:

A CORS preflight request is a CORS request that checks to see if the CORS protocol is understood.

It is an OPTIONS request using two HTTP request headers: Access-Control-Request-Method and Access-Control-Request-Headers, and the Origin header.

A preflight request is automatically issued by a browser when needed; in normal cases, front-end developers don't need to craft such requests themselves.

For cross-domain AJAX requests, the browser first needs to check with the remote server, whether it wants to accept a request using a specific method and/or specific request headers.

That happens via an OPTIONS request. And when the server signals in the response that the actual request the client wants to make is acceptable, the client then makes that request.



回答2:

Recently, I have met the same problem. I solved it using the following code:

import tornado.ioloop 
import tornado.web

class MainHandler(tornado.web.RequestHandler): 
    def set_default_headers(self):
        print('set headers!!')
        self.set_header('Access-Control-Allow-Origin', '*')
        self.set_header('Access-Control-Allow-Headers', '*')
        self.set_header('Access-Control-Max-Age', 1000)
        self.set_header('Content-type', 'application/json')
        self.set_header('Access-Control-Allow-Methods', 'POST, GET, OPTIONS')
        self.set_header('Access-Control-Allow-Headers',
                        'Content-Type, Access-Control-Allow-Origin, Access-Control-Allow-Headers, X-Requested-By, Access-Control-Allow-Methods')
    def OPTIONS(self):
        pass

application = tornado.web.Application([ (r"/", MainHandler), ])    
if name == "main":application.listen(8888)
    tornado.ioloop.IOLoop.instance().start()