用Django开发的API,在浏览器里可以正常访问,但在javascript里用GET访问,却报错如下:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
就是说脚本只能向加载它的站点发送HTTP请求。浏览器能GET到(直接在浏览器地址栏里访问)的资源,脚本不一定能GET到。举个例子,比如通过这个URL(http://tb2.bdstatic.com/tb/static-spage/widget/member_rank/member_rank_z_a0f387f.pnG),可以访问到百度的一张图片。你把这个URL用浏览器直接访问,或者写在HTML的image元素的src里,都是可以正常访问到这张图片。但用JS来GET,就会报错。
CORS机制规定,服务器要在HTTP头中添加Access-Control-Allow-Origin, Access-Control-Allow-Methods,来限制其他站点和可以访问资源的方法。再看看最初提到的那个报错,不就是服务器没有配置Access-Control-Allow-Origin么。
将支持CORS的站点地址添加到源服务器Access-Control-Allow-Origin,则该站点的JS,就能访问到源服务器中的资源。
[1]http://www.jianshu.com/p/4e17445d66e2
No 'Access-Control-Allow-Origin' header is present on the requested resource.
查了一下,其实这个问题水还不浅,下面来分析一下。
就是说脚本只能向加载它的站点发送HTTP请求。浏览器能GET到(直接在浏览器地址栏里访问)的资源,脚本不一定能GET到。举个例子,比如通过这个URL(http://tb2.bdstatic.com/tb/static-spage/widget/member_rank/member_rank_z_a0f387f.pnG),可以访问到百度的一张图片。你把这个URL用浏览器直接访问,或者写在HTML的image元素的src里,都是可以正常访问到这张图片。但用JS来GET,就会报错。
注意这个策略是浏览器策略,如果在其它非浏览器运行的脚本中,比如python,还是能GET到百度这个图片的。
这个策略是一个安全策略,没有它,就会发生cookie劫持(A站点获取B站点的cookie)一类的安全问题。但这个策略规定的那么死,A站点的JS又不能调用B开发的API,那API就没啥用了。如果一个站点不能访问另一站点的资源,互联网上的资源冗余得有多大!
CORS机制规定,服务器要在HTTP头中添加Access-Control-Allow-Origin, Access-Control-Allow-Methods,来限制其他站点和可以访问资源的方法。再看看最初提到的那个报错,不就是服务器没有配置Access-Control-Allow-Origin么。
将支持CORS的站点地址添加到源服务器Access-Control-Allow-Origin,则该站点的JS,就能访问到源服务器中的资源。
回到Django,利用Django的中间件,有更简单的方法能满足CORS机制,详见这里。
1. 在Django项目的跟目录(manage.py所在目录)下
pip install django-cors-headers
2. 在settings.py中配置CORS_ORIGIN_ALLOW_ALL,则允许所有站点来访问资源
INSTALLED_APPS = (
...
'corsheaders',
...
)
MIDDLEWARE_CLASSES = (
...
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
...
)
CORS_ORIGIN_ALLOW_ALL = True
开放了所有站点来访问资源,在HTTP头中,Access-Control-Allow-Origin被设置为"*"。 允许所有站点访问资源的做法并不安全,比如黑客写一段无穷个GET来访问资源的代码,就可能导致服务器瘫痪,所以还可以设置白名单:
CORS_ORIGIN_WHITELIST = (
'localhost:8083',
'hostname.example.com'
)
下面是Baidu在处理POST请求时的HTTP响应,它将Access-Control-Allow-Origin被设置为"*",看来Baidu还用了其它手段保证安全。
[1]http://www.jianshu.com/p/4e17445d66e2