"WARNING:tornado.access:405" 从 "localhost" 和 "file://" 来源停止 POST 错误

"WARNING:tornado.access:405" error stopping POST from both "localhost" and "file://" origins

这个问题与这个问题 (Tornado POST 405: Method Not Allowed) 非常相似,但该问题的简单答案仍然无效。侧边栏还有很多很多类似的问题-----> 与Tornado无关,也没有给我提供解决方案。

现在我在 OSX.

上使用 Firefox

我的龙卷风代码如下:

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()

如果我 运行 GET,它工作正常,但如果我使用 POST,我在客户端 HTTP/1.1 405 Method Not Allowed 和服务器端 WARNING:tornado.access:405 OPTIONS 收到错误].我已经在 file://index.htmllocalhost:8000/index.html 设置

中尝试 运行ning js

我的测试 js 是这样的:

//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);
});

我的 ajax 代码如下所示,如果有帮助的话:

//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 :: 如果我将龙卷风代码更改为等同于 GET POST 和 OPTION,它可以工作,但不正确

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

我不再收到错误,但是当我打印 self.request 时,我的 headers 似乎设置为 "OPTIONS" 不知何故

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'})

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

那将是 CORS pre-flight 请求。

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.

对于cross-domainAJAX请求,浏览器首先需要与远程服务器核对,是否要接受使用特定方法的请求and/or特定请求headers.

这是通过 OPTIONS 请求实现的。当服务器在响应中发出信号表明客户端想要发出的实际请求是可接受的时,客户端就会发出该请求。

最近遇到了同样的问题。我使用以下代码解决了它:

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()