0

I am writing simple web-site with js-client and a server side(python) I did everything to remove CORS error but nothing works. I wrote all needed headers for this but still get this error. So web-site should send a request to a server and get answer. Error:

Access to XMLHttpRequest at 'http://127.0.0.1:8000/' from origin 'null' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

myFile.html:

<!DOCTYPE html>
<html>
<head>
    <title>requestJs</title>
</head>
<body>
<button class="myButton">SEND</button>
<script type="text/javascript">
let theButton = document.querySelector(".myButton");
    theButton.addEventListener('click',function() {
  const xhr = new XMLHttpRequest();

xhr.onload = function() {
 alert(`Статус: ${xhr.status}; Результат: ${xhr.response}`)
};

xhr.onerror = function() {
  alert('Ошибка запроса');
};

xhr.open("GET", "http://127.0.0.1:8000/", true);
xhr.send(2);
    })

</script>
</body>
</html>

Server side:

import http.server as httpserver


class CORSHTTPRequestHandler(httpserver.SimpleHTTPRequestHandler):
    def send_head(self):
        """Common code for GET and HEAD commands.
        This sends the response code and MIME headers.
        Return value is either a file object (which has to be copied
        to the outputfile by the caller unless the command was HEAD,
        and must be closed by the caller under all circumstances), or
        None, in which case the caller has nothing further to do.
        """
        path = self.translate_path(self.path)
        f = None
        if os.path.isdir(path):
            if not self.path.endswith('/'):
                # redirect browser - doing basically what apache does
                self.send_response(301)
                self.send_header("Location", self.path + "/")
                self.end_headers()
                return None
            for index in "index.html", "index.html":
                index = os.path.join(path, index)
                if os.path.exists(index):
                    path = index
                    break
            else:
                return self.list_directory(path)
        ctype = self.guess_type(path)
        try:
            # Always read in binary mode. Opening files in text mode may cause
            # newline translations, making the actual size of the content
            # transmitted *less* than the content-length!
            f = open(path, 'rb')
        except IOError:
            self.send_error(404, "File not found")
            return None
        self.send_response(200)
        self.send_header("Content-type", ctype)
        fs = os.fstat(f.fileno())
        self.send_header("Content-Length", str(fs[6]))
        self.send_header("Last-Modified", self.date_time_string(fs.st_mtime))
        self.send_header("Access-Control-Allow-Origin:", "*")
        self.send_header("Access-Control-Allow-Methods:", "GET,HEAD,PUT,PATCH,POST,DELETE")
        self.send_header("Access-Control-Allow-Headers:", "Content-Type, Access-Control-Allow-Origin, xxx")
        self.end_headers()
        return f


if __name__ == "__main__":
    import os
    import socketserver

    import sys

    PORT = int(sys.argv[1]) if len(sys.argv) > 1 else 8000

    handler = CORSHTTPRequestHandler

    httpd = socketserver.TCPServer(("", PORT), handler)

    print(f"serving at port {PORT}")
    httpd.serve_forever()

Help me please, what is my problem?

  • Have you checked why your website's origin is `null`? Can you confirm, that the response contains all the headers you set? – acincognito Jan 07 '21 at 12:53
  • And are you sure that `self.send_header("Access-Control-Allow-Origin:", "*")` shouldn't be `self.send_header("Access-Control-Allow-Origin", "*")`? – acincognito Jan 07 '21 at 12:54
  • @acincognito I changed headers as you said, but I don't understand this thing about origin: null, could you please explain what does it mean and which headers should I add? And do I have to add headers in js request? – leocoolguy 0 Jan 07 '21 at 13:03
  • See [Access-Control-Allow-Headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers). I wonder if you should *not* be specifying this at all. – Booboo Jan 07 '21 at 13:05
  • @Booboo thanks will read that. Btw is there a way how to not face cors at all? Because I don't think so that every web site does this. And I guess there is a special reason why they appear – leocoolguy 0 Jan 07 '21 at 13:12
  • You only need CORS if you `xhr` request is coming from JavaScript loaded from a domain other than the domain to which the request is being made. If the request is being made back up to the host from where it was loaded, you don't need it, – Booboo Jan 07 '21 at 13:22
  • @Booboo So my Js client should have the same domain as my server has? Did I understand you correctly ? – leocoolguy 0 Jan 07 '21 at 13:48
  • No. The client can be anywhere. The JavaScript is being loaded from some server to the client and once on the client an `xhr` request is being made to another server. It is when this second server is not the same server from where the JavaScript was loaded that the second server must permit CORS, An alternative to getting CORS to work is `JSONP`, See [What is JSONP, and why was it created?](https://stackoverflow.com/questions/2067472/what-is-jsonp-and-why-was-it-created) – Booboo Jan 07 '21 at 13:59
  • @Booboo Oh so I'm not able to do this when I am doing it on local server(on my single computer)? And btw thank you for your answers with your links, I appreciate that – leocoolguy 0 Jan 07 '21 at 14:01
  • Sure, you can do CORS on your local server. First question: Are you loading the JavaScript from 127.0.0.1:8000 or from somewhere else? – Booboo Jan 07 '21 at 14:04
  • @Booboo or I guess I understood. No, js-client is a small script in html file, and I open this html file like normal file. So I guess I have to load this file from python server too? – leocoolguy 0 Jan 07 '21 at 14:08
  • Note: don't use XMLHttpRequest, use the Fetch API for things like this (the replacement for XMLHttpRequest with universal browser support since 2016). – Mike 'Pomax' Kamermans Nov 25 '22 at 22:34

1 Answers1

0

This is not a comprehensive answer but it might help.

CORS is entirely a browser feature. You can turn it off in your browser. I suggest the first step therefore is to launch a CORS-free browser to test your app. Make sure not to open your banking page in this browser session though, it isn't safe!

google-chrome --user-data-dir=/var/tmp/Chrome --disable-web-security

If everything works then then issue is just CORS. If you are only running in a dev environment, you can just do this everytime even. If you are running in production, the easiest option is often just to use a gateway that fixes this stuff for you. That's how I got mine working.

If the above isn't good enough and you want to debug, remember that all browser CORS requests are initiated by a preflight OPTIONS requests. Sometimes that's where the problem comes in. Make sure your server is able to handle and respond to OPTIONS, and check that it is responding correctly.

Neil
  • 3,020
  • 4
  • 25
  • 48
  • Thank you for the answer, but if I turn off CORS on my browser it will probably work but only for me! But I am not the only person who is gonna use this website so my clients won't be able to recieve the answer from the server? – leocoolguy 0 Jan 07 '21 at 12:15
  • That's why I said you need another solution for production! For me, I used the krakend gateway API, and it made all the CORS stuff just work. – Neil Jan 07 '21 at 12:18
  • But how is it possible to solve normally? I mean how normal big sites solve that? I didn't think that I would have so many problems sending simple requests especially in localhost – leocoolguy 0 Jan 07 '21 at 12:22
  • Big sites will DEFINITELY use an API gateway. Small sites don't need CORS at all because they only have one origin. You've built a system that has two origins, so already you have to start looking at orchestration/load balancing/ request forwarding etc. It is possible to manually wrangle headers to get this to work, but as I said, I have no idea how to do that. Add a bounty and hope someone else knows. But manually wrangling headers will not scale. If your site is never going to need to scale, consider going monolith and avoiding these issues. If it is, get a gateway. – Neil Jan 07 '21 at 13:07
  • I also didn't think I would have all these issues first time I tried microservices. It's not the requests or localhost that is the problem though. You can send the exact same request from CURL or Postman and have no issues. It's ajax calls from Javascript in the browser that cause these problems. Have a look at JSONP if you want to understand the history. – Neil Jan 07 '21 at 13:11
  • "You've built a system that has two origins", I didn't want to do that, I just want to test it locally on my computer, and I don't know to make one origin from that. Because I open html file normally and I guess my computer is working like the server but then I use a python... So is there a way to change it? To just have one origin(python server) locally? – leocoolguy 0 Jan 07 '21 at 14:06
  • yes. Serve the html from the Python server. – Neil Jan 07 '21 at 14:08
  • That's what I meant by monolith – Neil Jan 07 '21 at 14:10
  • Then you shouldn't need CORS at all (get rid of all your CORS-related headers). I believe your browser is confused and not recognizing that you are making an `xhr` request back up to the same server because you have specified in your `xhr` request an *absolute* URL. Try specifying a *relative* URL: `xhr.open("GET", "/", true);` – Booboo Jan 07 '21 at 14:12
  • Let me know how it turns out. – Booboo Jan 07 '21 at 14:16
  • Hoping that works but suspect it won't. I think the javascript has to be served by the python server (not just opened in the filesystem). There's an example of serving html with httpsimpleserver down on this page https://stackabuse.com/serving-files-with-pythons-simplehttpserver-module/ – Neil Jan 07 '21 at 14:25
  • @Booboo Hello, everything works fine! thank you! – leocoolguy 0 Jan 08 '21 at 21:27
  • This is terrible advice, and doesn't actually solve the problem. – Mike 'Pomax' Kamermans Nov 25 '22 at 22:30