zoukankan      html  css  js  c++  java
  • 65.django中关于跨域访问设置

    django中关于跨域访问设置

    记一次 CORS 跨域请求出现 OPTIONS 请求的问题及解决方法
    今天前后端在联调接口的时候,发生了跨域请求资源获取不到的问题。
    首先说明下跨域问题的由来。引自HTTP 访问控制 的一段话:
    
    当 Web 资源请求由其它域名或端口提供的资源时,会发起跨域 HTTP 请求(cross-origin HTTP request)。
    比如,站点 http://domain-a.com 的某 HTML 页面通过 <img> 的 src 请求 http://domain-b.com/image.jpg。网络上,很多页
    面从其他站点加载各类资源(包括 CSS、图片、JavaScript 脚本)。
    出于安全考虑,浏览器会限制脚本中发起的跨域请求。比如,使用 XMLHttpRequest 和 Fetch 发起的 HTTP 请求必须遵循同源策略。
    因此,Web 应用通过 XMLHttpRequest 对象或 Fetch 仅能向同域资源发起 HTTP 请求。 
    既然知道了导致问题的原因,就开始解决吧。
    笔者使用的 是 Django 框架。github 上面已经有人分享了解决办法,就是 django-cors-headers。我们直接
    
    pip install django-cors-headers 
    安装一下呗。
    安装好了以后,需要我们去 settings 文件中去配置一下。常见的配置如下:
    
    先在 INSTALLED_APPS 中引入 corsheaders:
    INSTALLED_APPS = (
        ...
        'corsheaders',
        ...
    )
    接着,在 MIDDLEWARE_CLASSES 里面加入 CorsMiddleware 中间件:
    MIDDLEWARE_CLASSES = [
        ...
        'corsheaders.middleware.CorsMiddleware',  # cors
        'django.middleware.common.CommonMiddleware',
        ...
    然后,配置下一些基本参数:
    CORS_ORIGIN_ALLOW_ALL = True
    CORS_ALLOW_CREDENTIALS = True
    一些文章还有配置 CORS_ORIGIN_WHITELIST 参数。
    
    笔者也是看了别人的解决方法,之前也是实践过了。配置好这三个参数就OK了。本来也以为大工告成了。没想到,居然没解决!!!
    怎么回事?
    通过追踪请求日志,发现每次客户端请求接口的时候,都会有一个 OPTIONS 请求。
    
    为什么会有 OPTIONS 请求?
    原来,产生 OPTIOINS 请求的原因是:自定义 Headers 头信息导致的。为了限制接口的访问,我在 request 中间件里面加了一层过滤
    ,通过判断 headers 中是否有约定好的字段及其对应的值(比如:key为 aaa, value为 bbb),如果有,就默认可以请求。设置完自
    定义 header 字段后,问题就出现了:原来的简单请求会变成预检请求。
    
    XHR对象对于HTTP跨域请求有三种:简单请求、Preflighted 请求、Preflighted 认证请求。简单请求不需要发送OPTIONS嗅探请求,但
    只能按发送简单的GET、HEAD或POST请求,且不能自定义HTTP Headers。Preflighted 请求和认证请求,XHR会首先发送一个OPTIONS嗅
    探请求,然后XHR会根据OPTIONS请求返回的Access-Control-*等头信息判断是否有对指定站点的访问权限,并最终决定是否发送实际请求信息。
    浏览器会去向 Server 端发送一个 OPTIONS 请求,看 Server 返回的 "Access-Control-Allow-Headers" 是否有自定义的 header 字
    段。因为我之前没有返回自定义的字段,所以,默认是不允许的,造成了客户端没办法拿到数据。
    既然已经知道了原因,且知道了解决思路,就动手干吧。通过阅读 django-cors-headers 的源码后,发现 **corsheaders/middleware.py 
    ** 里面已经有实现了,那就不再重复造轮子了。
    
    def process_response(self, request, response):
            """
            Add the respective CORS headers
            """
            origin = request.META.get('HTTP_ORIGIN')
            if not origin:
                return response
    
            enabled = getattr(request, '_cors_enabled', None)
            if enabled is None:
                enabled = self.is_enabled(request)
    
            if not enabled:
                return response
    
            # todo: check hostname from db instead
            url = urlparse(origin)
    
            if conf.CORS_ALLOW_CREDENTIALS:
                response[ACCESS_CONTROL_ALLOW_CREDENTIALS] = 'true'
    
            if (
                not conf.CORS_ORIGIN_ALLOW_ALL and
                not self.origin_found_in_white_lists(origin, url) and
                not self.origin_found_in_model(url) and
                not self.check_signal(request)
            ):
                return response
    
            if conf.CORS_ORIGIN_ALLOW_ALL and not conf.CORS_ALLOW_CREDENTIALS:
                response[ACCESS_CONTROL_ALLOW_ORIGIN] = "*"
            else:
                response[ACCESS_CONTROL_ALLOW_ORIGIN] = origin
                patch_vary_headers(response, ['Origin'])
    
            if len(conf.CORS_EXPOSE_HEADERS):
                response[ACCESS_CONTROL_EXPOSE_HEADERS] = ', '.join(conf.CORS_EXPOSE_HEADERS)
    
            if request.method == 'OPTIONS':
                response[ACCESS_CONTROL_ALLOW_HEADERS] = ', '.join(conf.CORS_ALLOW_HEADERS)
                response[ACCESS_CONTROL_ALLOW_METHODS] = ', '.join(conf.CORS_ALLOW_METHODS)
                if conf.CORS_PREFLIGHT_MAX_AGE:
                    response[ACCESS_CONTROL_MAX_AGE] = conf.CORS_PREFLIGHT_MAX_AGE
    
            return response
    看完后,发现只要配置下 CORS_ALLOW_HEADERS 就好。
    
    from corsheaders.defaults import default_headers
    
    CORS_ALLOW_HEADERS = default_headers + (
        'aaa'
    )
    
    参考:
        https://github.com/adamchainz/django-cors-headers   # 如何设置
        https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS # 跨域产生原因
    转载: 
        https://www.cnblogs.com/scharfsinnig/archive/2017/04/27/6769737.html # 一个解决案例
    
  • 相关阅读:
    为什么MySQL死锁检测会严重降低TPS
    OneProxy FAQ 之proxy-user-list
    OneProxy主从延迟检测
    MySQL和OneSQL并行插入性能对比
    天下文章一大抄,你抄我来我抄它
    卖软件的尴尬
    死锁检测为什么耗时?
    28岁的我
    突然想把一生都奉献给MySQL
    如何确定编码风格?
  • 原文地址:https://www.cnblogs.com/liuzhanghao/p/13217889.html
Copyright © 2011-2022 走看看