I'm trying to talk to a web app hosted on PythonAnywhere. It's a low-bandwidth, low frequency connection so I'm fine with an http interface -- and it works fine over http from a browser. However, I can't seem to get to the same service running on the PythonAnywhere host running in the cloud.
If I run the server locally, this works:
import socket
s = socket.socket()
s.connect(('127.0.0.1', 8080))
s.send('GET /check/nicky HTTP/1.1\r\n\r\n')
print (s.recv(1024))
# 'HTTP/1.0 200 OK\r\nDate: Sat, 01 Jun 2019 23:45:14 GMT\r\nServer: WSGIServer/0.2 CPython/3.7.2\r\nContent-Type: application/json\r\nContent-Length: 19\r\n\r\n{"nicky": [0, 120]}'
However if I use socket.getaddrinfo()
on the pythonanywhere URL (to replace the address in s.connect()
above) I get a 'bad request' response:
'HTTP/1.1 400 Bad Request\r\nServer: openresty/1.9.15.1\r\nDate: Sat, 01 Jun 2019 23:49:48 GMT\r\nContent-Type: text/html\r\nContent-Length: 179\r\nConnection: close\r\n\r\n<html>\r\n<head><title>400 Bad Request</title></head>\r\n<body bgcolor="white">\r\n<center><h1>400 Bad Request</h1></center>\r\n<hr><center>openresty/1.9.15.1</center>\r\n</body>\r\n</html>\r\n'
The server functions fine if I type the same request into a browser -- but trying to do it programmatically always fails in this manner.
Is this some kind of proxy or port-forwarding magic I don't know about? The pythonanwhere account in question is a freebie.
** In case it's not clear ** @Steffen Ulrich's diagnosis is correct. I ended up using https://github.com/micropython/micropython-lib/tree/master/urequests, the micropython clone of requests, and that solved the problem.
s.send('GET /check/nicky HTTP/1.1\r\n\r\n') .. 'HTTP/1.1 400 Bad Request\r\nServer: openresty/1.9.15.1\r\n ...
The server is right. What you send is not a correct HTTP request. For HTTP/1.1
the Host
field is required in the HTTP header.
If you add this the request might work but you might run into various other troubles, like missing support for chunked response body, assumption that everything will be done in a single read ...
While you might try to deal with all of this in your own code I recommend that you use instead an existing HTTP library, like requests.
If you really want to write your own HTTP layer I really recommend to read and understand the standard before implementing it, that's what standards are for. For HTTP/1.1
these are RFC 7230 and following RFC's.