CORS (Cross Origin Resource Sharing) allows access to resources from other domains, a good use case for this is a web app trying to fetch data from an API on another domain. CORS is only required when trying to fetch data from a browser, as browsers by default will block requests to different origins (domains).
CORS uses HTTP headers to tell the browser if it has permission to fetch the resources.
Browsers use a preflight header to determine if it has permission to interact with
the domain. This preflight header takes the form of a OPTIONS
request, usually
sending the following HTTP headers to the server:
Access-Control-Request-Method
: The method of the request, e.g. GET
if trying to get dataAccess-Control-Request-Headers
: The headers that will be sent to the serverThe response will usually contain the following headers:
Access-Control-Allow-Origin
: The origins that are allowed to access
the resource (specify ’*’ for all)Access-Control-Allow-Methods
: The methods that are allowed on the resource, e.g. "GET,POST,OPTIONS"
, remember to include OPTIONS
in it,
as its required for the preflight headerAccess-Control-Allow-Headers
: The additional headers that are
allowed on the resourcePython has a simple HTTP server built-in, that can be extended easily.
It can be imported like so:
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
BaseHTTPServer is a base class that needs to be subclassed to do anything useful. The most useful methods that can be implemented include:
do_GET
: Handles a GET requestdo_POST
: Handles a POST requestdo_OPTIONS
: Handle an OPTIONS request (which is the preflight request for CORS)We create a small function called _send_cors-headers
which sends the required headers.
Its important to add all the methods that you wish to use with the API in the
Access-Control-Allow-Methods
header, which in this case is GET,POST,OPTIONS
.
The do_OPTIONS
method only needs to return a 200 response, CORS only
cares about what headers it gets from the OPTIONS request, not the actual response
body.
#!/usr/bin/env python3
from http.server import BaseHTTPRequestHandler, HTTPServer
from json import dumps
""" The HTTP request handler """
class RequestHandler(BaseHTTPRequestHandler):
def _send_cors_headers(self):
""" Sets headers required for CORS """
self.send_header("Access-Control-Allow-Origin", "*")
self.send_header("Access-Control-Allow-Methods", "GET,POST,OPTIONS")
self.send_header("Access-Control-Allow-Headers", "x-api-key,Content-Type")
def send_dict_response(self, d):
""" Sends a dictionary (JSON) back to the client """
self.wfile.write(bytes(dumps(d), "utf8"))
def do_OPTIONS(self):
self.send_response(200)
self._send_cors_headers()
self.end_headers()
def do_GET(self):
self.send_response(200)
self._send_cors_headers()
self.end_headers()
response = {}
response["status"] = "OK"
self.send_dict_response(response)
def do_POST(self):
self.send_response(200)
self._send_cors_headers()
self.send_header("Content-Type", "application/json")
self.end_headers()
dataLength = int(self.headers["Content-Length"])
data = self.rfile.read(dataLength)
print(data)
response = {}
response["status"] = "OK"
self.send_dict_response(response)
print("Starting server")
httpd = HTTPServer(("127.0.0.1", 8000), RequestHandler)
print("Hosting server on port 8000")
httpd.serve_forever()