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