在用python3创建简单http服务器时,碰到跨域问题,网上找的大多数方法都不行,下面整理出解决方法,亲测有效。
一、代码
import json
from http.server import HTTPServer
from http.server import SimpleHTTPRequestHandler
import socketserver
import socket
class MyRequestHandler(SimpleHTTPRequestHandler):
def _send_cors_headers(self):
""" Sets headers required for CORS """
self.send_header('Content-type', 'application/json')
self.send_header("Access-Control-Allow-Origin", "*")
self.send_header("Access-Control-Allow-Methods", "*")
self.send_header("Access-Control-Allow-Headers", "Authorization, Content-Type")
def do_GET(self):
print(self.path)
if self.path == "/get_ipaddr":
req = {'code': "0", 'msg': 'OK', 'ipaddr': socket.gethostbyname(socket.gethostname())}
else:
req = {'code': "4103", 'msg': 'path error'}
self.send_response(200)
self._send_cors_headers()
self.end_headers()
rspstr = json.dumps(req)
self.wfile.write(rspstr.encode("utf-8"))
def do_OPTIONS(self):
self.send_response(200)
self._send_cors_headers()
self.end_headers()
def do_POST(self):
if self.path == "/login":
req = {'code': "0", 'msg': 'OK'}
else:
req = {'code': "4103", 'msg': 'path error'}
self.send_response(200)
self._send_cors_headers()
self.end_headers()
rspstr = json.dumps(req)
self.wfile.write(rspstr.encode("utf-8"))
if __name__ == '__main__':
server_host = '127.0.0.1'
server_port = 8000
httpd = socketserver.TCPServer((server_host, server_port), MyRequestHandler)
print('exe_server started on ' + str(server_host) + ' server_port:' + str(server_port))
httpd.serve_forever()
说明: 解决跨域的关键代码:self.send_header("Access-Control-Allow-Headers", "Authorization, Content-Type")
二、HTTP 响应首部字段说明
1. Access-Control-Allow-Origin
响应首部中可以携带一个 Access-Control-Allow-Origin 字段,其语法如下:
Access-Control-Allow-Origin: | *
其中,origin 参数的值指定了允许访问该资源的外域 URI。对于不需要携带身份凭证的请求,服务器可以指定该字段的值为通配符,表示允许来自所有域的请求。
例如,下面的字段值将允许来自 http://mozilla.com 的请求:
Access-Control-Allow-Origin: http://mozilla.com
如果服务端指定了具体的域名而非“*”,那么响应首部中的 Vary 字段的值必须包含 Origin。这将告诉客户端:服务器对不同的源站返回不同的内容。
2. Access-Control-Expose-Headers
译者注:在跨源访问时,XMLHttpRequest对象的getResponseHeader()方法只能拿到一些最基本的响应头,Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma,如果要访问其他头,则需要服务器设置本响应头。
Access-Control-Expose-Headers 头让服务器把允许浏览器访问的头放入白名单,例如:
Access-Control-Expose-Headers: X-My-Custom-Header, X-Another-Custom-Header
这样浏览器就能够通过getResponseHeader访问X-My-Custom-Header和 X-Another-Custom-Header 响应头了。
3. Access-Control-Max-Age
Access-Control-Max-Age 头指定了preflight请求的结果能够被缓存多久,请参考本文在前面提到的preflight例子。
Access-Control-Max-Age:
delta-seconds 参数表示preflight请求的结果在多少秒内有效。
4. Access-Control-Allow-Credentials
Access-Control-Allow-Credentials 头指定了当浏览器的credentials设置为true时是否允许浏览器读取response的内容。当用在对preflight预检测请求的响应中时,它指定了实际的请求是否可以使用credentials。请注意:简单 GET 请求不会被预检;如果对此类请求的响应中不包含该字段,这个响应将被忽略掉,并且浏览器也不会将相应内容返回给网页。
Access-Control-Allow-Credentials: true
上文已经讨论了附带身份凭证的请求。
5. Access-Control-Allow-Methods
Access-Control-Allow-Methods 首部字段用于预检请求的响应。其指明了实际请求所允许使用的 HTTP 方法。
Access-Control-Allow-Methods: [, ]*
相关示例见这里。
6. Access-Control-Allow-Headers
Access-Control-Allow-Headers 首部字段用于预检请求的响应。其指明了实际请求中允许携带的首部字段。
Access-Control-Allow-Headers: [, ]*