add a decorator for CORS.

This commit is contained in:
ztk 2017-10-17 18:05:23 +08:00
parent c5cdcf0f95
commit 49fb34ca2b
3 changed files with 126 additions and 0 deletions

50
examples/cors.html Normal file
View File

@ -0,0 +1,50 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Cors Example</title>
</head>
<body>
<script>
var xhr1 = new XMLHttpRequest();
xhr1.onload = function () {
console.log(xhr1.responseText)
};
xhr1.open('GET', 'http://127.0.0.1:8000/');
xhr1.send();
var xhr2 = new XMLHttpRequest();
xhr2.onload = function () {
console.log(xhr2.responseText)
};
xhr2.open('GET', 'http://127.0.0.1:8000/t2');
xhr2.send();
</script>
<script>
var ws = new WebSocket('ws://127.0.0.1:8000/feed'),
messages = document.createElement('ul');
ws.onmessage = function (event) {
var messages = document.getElementsByTagName('ul')[0],
message = document.createElement('li'),
content = document.createTextNode('Received: ' + event.data);
message.appendChild(content);
messages.appendChild(message);
};
document.body.appendChild(messages);
window.setInterval(function () {
var data = 'bye!';
ws.send(data);
var messages = document.getElementsByTagName('ul')[0],
message = document.createElement('li'),
content = document.createTextNode('Sent: ' + data);
message.appendChild(content);
messages.appendChild(message);
}, 1000);
</script>
</body>
</html>

31
examples/cors_example.py Normal file
View File

@ -0,0 +1,31 @@
from sanic import Sanic
from sanic import response
app = Sanic(__name__)
@app.route("/")
@response.cors()
async def test(request):
return response.json({"test": True})
@app.route("/t2")
@response.cors()
def test2(request):
return response.json({"test": True})
@app.websocket('/feed')
@response.cors()
async def feed(request, ws):
while True:
data = 'hello!'
print('Sending: ' + data)
await ws.send(data)
data = await ws.recv()
print('Received: ' + data)
if __name__ == '__main__':
app.run(host="0.0.0.0", port=8000)

View File

@ -1,5 +1,7 @@
from mimetypes import guess_type from mimetypes import guess_type
from os import path from os import path
from functools import wraps
from inspect import isawaitable
try: try:
from ujson import dumps as json_dumps from ujson import dumps as json_dumps
@ -9,6 +11,7 @@ except:
from aiofiles import open as open_async from aiofiles import open as open_async
from sanic.cookies import CookieJar from sanic.cookies import CookieJar
from sanic.constants import HTTP_METHODS
COMMON_STATUS_CODES = { COMMON_STATUS_CODES = {
200: b'OK', 200: b'OK',
@ -427,3 +430,45 @@ def redirect(to, headers=None, status=302,
status=status, status=status,
headers=headers, headers=headers,
content_type=content_type) content_type=content_type)
def cors(origin=None, allow_methods=None):
if isinstance(allow_methods, (list, tuple, set)):
allow_methods = ', '.join(
filter(
lambda x: x in HTTP_METHODS,
map(
lambda x: x.upper(),
allow_methods
)
)
)
elif allow_methods:
raise ValueError('allow_methods must be instance of list, tuple or set.')
cors_headers = {
'Access-Control-Allow-Credentials': 'true',
'Access-Control-Allow-Methods': allow_methods or 'GET',
'Access-Control-Allow-Origin': origin or '*'
}
def decorator(fn):
@wraps(fn)
def wrap(*args, **kwargs):
res = fn(*args, **kwargs)
if isinstance(res, BaseHTTPResponse):
res.headers.update(cors_headers)
return res
elif isawaitable(res):
async def make_cors():
response = await res
response.headers.update(cors_headers)
return response
return make_cors()
return res
return wrap
return decorator