Django前后端打通

07-19 1852阅读

跨域问题

【 0 】前言

Django前后端打通

​ 同源策略(Same Origin Policy)是浏览器安全策略的重要组成部分,它限制了来自不同源的网页之间的数据交互,以防止恶意攻击。当一个网页尝试执行与它的源(即协议、域名和端口)不一致的请求时,浏览器会出于安全考虑拦截这个请求。

​ 跨域资源共享(CORS, Cross-Origin Resource Sharing)是一个W3C规范,它允许某些跨源请求,如Ajax,从而克服了Ajax只能同源使用的限制。CORS需要浏览器和服务器同时支持,基本思想是使用自定义的HTTP头来让浏览器和服务器进行通信。

​ 在Django项目中解决跨域问题,可以通过多种方法,包括手动编写中间件以及使用第三方库。你给出的示例展示了如何手动编写一个CORS中间件,以及如何使用django-cors-headers这个流行的第三方库来简化CORS的设置。

手动编写CORS中间件:

​ 中间件代码示例中,通过向响应头中添加适当的CORS相关头部,允许来自任何源的请求("Access-Control-Allow-Origin": "*")。同时,对于OPTIONS请求(预检请求),该中间件还允许所有的方法和头部。

使用django-cors-headers库:

  1. 安装库:pip install django-cors-headers
  2. 在settings.py中添加'corsheaders'到INSTALLED_APPS。
  3. 在settings.py的MIDDLEWARE中添加'corsheaders.middleware.CorsMiddleware',并确保它在其他中间件之前(特别是在CommonMiddleware之前)。
  4. 配置CORS选项。例如,设置CORS_ORIGIN_ALLOW_ALL为True来允许所有源的请求,或者你可以指定一个允许源的列表。CORS_ALLOW_METHODS和CORS_ALLOW_HEADERS分别定义了允许的HTTP方法和头部。

​ 请注意,出于安全考虑,通常不建议在生产环境中设置CORS_ORIGIN_ALLOW_ALL为True,除非你完全理解可能的安全风险。在生产环境中,最好明确指定允许的源。

​ 另外,值得注意的是,虽然CORS解决了浏览器端的跨域问题,但服务器端仍然需要验证请求的有效性,以防止潜在的安全威胁,如CSRF攻击。因此,即使启用了CORS,也不应忽视服务器端的安全性措施。

  • xss:跨站脚本攻击

  • csrf:跨站请求伪造

  • cors:跨域资源共享

    # 同源策略(Same origin policy)是一种约定,它规定了 请求的url地址,必须与浏览器上的url地址处于同域上,也就是域名,端口,协议相同,如果不一致,请求会发送成功,后端会正常响应,但是浏览器会拦截
    #  浏览器对非同源请求返回的结果做了拦截
    # 只要做前后端分离,就会出跨域
    # 解决跨域问题
    	-CORS :跨域资源共享  咱们讲的方式   向响应头中加数据,允许跨域
        	- 后端代码处理
            - nginx代理
        -JSONP :利用有的标签没有跨域问题 script  img
        -websocket:长链接,不存在跨域
        -前端代理:开发阶段用,上线不用
        
        
    # cors如何解决跨域
    	-需要服务端支持---》就是服务端再响应头中加数据即可
        
    # CORS基本流程
    	CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)
    	简单请求,只发送一次:
        非简单请求发送两次,第一次是OPTIONS预检请求,第二次是真正的请求
    # 什么是简单,什么是非简单
    #请求方法是以下三种方法之一:
        HEAD
        GET
        POST
    # HTTP的头信息不超出以下几种字段:
        Accept
        Accept-Language
        Content-Language
        Last-Event-ID
        Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
        
    # 请求头中带了 token ,所有请求都是非简单
    ### 解决跨域---统一写个中间件--》处理所有跨域
    from django.utils.deprecation import MiddlewareMixin
    class CorsMiddleWare(MiddlewareMixin):
        def process_response(self,request,response):
            if request.method=="OPTIONS":
                #可以加*
                response["Access-Control-Allow-Headers"]="*"
                res['Access-Control-Allow-Methods'] = '*'
            response["Access-Control-Allow-Origin"] = "*"
            return response
    	
        
    # 第三方解决方案
    	# 1、使用pip安装
    	pip install django-cors-headers
        #2、添加到setting的app中
        INSTALLED_APPS = (
            ...
            'corsheaders',
            ...
        )
      #3、添加中间件
        MIDDLEWARE = [  
            ...
            'corsheaders.middleware.CorsMiddleware',
            ...
        ]
    4、setting下面添加下面的配置
    CORS_ORIGIN_ALLOW_ALL = True
    CORS_ALLOW_METHODS = (
    	'DELETE',
    	'GET',
    	'OPTIONS',
    	'PATCH',
    	'POST',
    	'PUT',
    	'VIEW',
    )
    CORS_ALLOW_HEADERS = (
    	'XMLHttpRequest',
    	'X_FILENAME',
    	'accept-encoding',
    	'authorization',
    	'content-type',
    	'dnt',
    	'origin',
    	'user-agent',
    	'x-csrftoken',
    	'x-requested-with',
    	'Pragma',
    	'token'
    )
    

    【 1 】解释

    ​ Access-Control-Allow-Headers、Access-Control-Allow-Methods 和 Access-Control-Allow-Origin 是三个与跨源资源共享(CORS)相关的 HTTP 响应头。它们各自有不同的作用和使用方法。

    1. Access-Control-Allow-Origin

    作用:

    • 用于指定哪些源(域名、协议和端口)有权限访问该资源。

      使用方法:

      • 如果服务器希望允许来自特定源的请求,如 https://example.com,可以返回以下响应头:
        Access-Control-Allow-Origin: https://example.com
        
        • 如果服务器希望允许来自任何源的请求(这通常在生产环境中是不安全的),可以返回:
          Access-Control-Allow-Origin: *
          

          2. Access-Control-Allow-Methods

          作用:

          • 列出哪些 HTTP 方法(如 GET、POST、PUT、DELETE 等)允许跨源请求。

            使用方法:

            • 如果服务器只允许 GET 和 POST 方法,可以返回以下响应头:
              Access-Control-Allow-Methods: GET, POST
              
              • 这个响应头通常与预检请求(OPTIONS 请求)一起使用,以检查服务器是否允许跨源请求中使用的特定 HTTP 方法。

                3. Access-Control-Allow-Headers

                作用:

                • 用于告知浏览器在跨域请求中,所允许的请求头字段(Request Header)。

                  使用方法:

                  • 如果浏览器请求包括 Access-Control-Request-Headers 字段,则 Access-Control-Allow-Headers 字段是必需的。它的值是一个逗号分隔的字符串,表明服务器支持的所有头信息字段,不限于浏览器在“预检”中请求的字段。
                  • 例如,如果服务器允许跨域请求时使用的请求头字段是 Content-Type 和 Authorization,可以返回以下响应头:
                    Access-Control-Allow-Headers: Content-Type, Authorization
                    

                    总结

                    • Access-Control-Allow-Origin 用于指定哪些源可以访问资源。
                    • Access-Control-Allow-Methods 用于指定哪些 HTTP 方法允许跨源请求。
                    • Access-Control-Allow-Headers 用于告知浏览器在跨域请求中,所允许的请求头字段。

                      ​ 这三个响应头通常一起使用,以确保跨源请求的安全性和可访问性。同时,它们也遵循 CORS 规范,确保浏览器和服务器之间的正确交互。

                      【 2 】跨域问题

                      【 1 】笨办法

                      • Access-Control-Allow-Origin

                      • 在子路由的视图类

                        from rest_framework.views import APIView
                        from lufy.utils.utils_response import APIResponse 	
                        class CoreView(APIView):
                            def get(self, request, *args, **kwargs):
                                # return APIResponse(name="shazi",password='123123132',token='asdas.da.dasd')
                                # return APIResponse(results=[{"user":'132'},{"hobby":['music','running']}])
                                return APIResponse(headers={"hobby":['music','running']})
                        
                        • 在HomeView.vue

                            
                              

                          首页

                          {{ dataFromServer.message }}

                          import { reactive, onMounted } from 'vue'; import axios from 'axios'; // 使用 reactive 来创建响应式的数据对象 const res = reactive({ message: '' }); // 在 onMounted 生命周期钩子中发送请求 onMounted(async () => { try { const response = await axios.get('http://127.0.0.1:8000/user/option/', { headers: { // token: 'asd.fas.sadas' // 在请求头中添加自定义的 token } }); res.message = response.data.message; // 这里可以处理响应的其他数据 console.log(response); } catch (error) { console.error('Error fetching data:', error); // 在这里你可以选择以某种方式通知用户或处理错误 } }); /* 你的样式代码 */

                          Django前后端打通

                          • 解决方法

                            from rest_framework.views import APIView
                            from lufy.utils.utils_response import APIResponse 
                            class CoreView(APIView):
                                def get(self, request, *args, **kwargs):
                                    # # return APIResponse(headers={"hobby":['music','running']})
                                    # No 'Access-Control-Allow-Origin' header is present on the requested resource.
                                    return APIResponse(headers={"Access-Control-Allow-Origin": '*'})
                            

                            Django前后端打通

                            • Access-Control-Allow-Headers

                            • 用于告知浏览器在跨域请求中,所允许的请求头字段

                            • urls.py

                              from django.urls import path
                              from . import views
                              from .views import LoggerView, ExceptionView,ResponseView,CoreView,core_view
                              urlpatterns = [
                                  # 日志
                                  path('logg/', LoggerView.as_view(), name='home'),
                                  # 异常
                                  path('except/', ExceptionView.as_view()),
                                  # 响应方法
                                  path('ponse/', ResponseView.as_view()),
                                  # 跨域
                                  path('core/', CoreView.as_view()),
                                  path('option/', core_view),
                              ]
                              
                              • views.py

                                from rest_framework.views import APIView
                                from lufy.utils.utils_response import APIResponse 
                                def core_view(request):
                                    res = HttpResponse("ok")
                                    res['Access-Control-Allow-Origin'] = '*'
                                    if request.method =='OPTIONS':
                                        res['Access-Control-Allow-Headers'] = '*'
                                    return res
                                

                                Django前后端打通

                                • 我现在要使用别的请求方法比如put、delete

                                  import { reactive, onMounted } from 'vue';
                                  import axios from 'axios';
                                  // 使用 reactive 来创建响应式的数据对象
                                  const res = reactive({
                                    message: ''
                                  });
                                  // 在 onMounted 生命周期钩子中发送请求
                                  onMounted(async () => {
                                    try {
                                      const response = await axios.put('http://127.0.0.1:8000/user/option/', {
                                        headers: {
                                          token: 'asd.fas.sadas' // 在请求头中添加自定义的 token
                                        }
                                      });
                                      res.message = response.data.message;
                                      // 这里可以处理响应的其他数据
                                      console.log(response);
                                    } catch (error) {
                                      console.error('Error fetching data:', error);
                                      // 在这里你可以选择以某种方式通知用户或处理错误
                                    }
                                  });
                                  
                                  

                                  Django前后端打通

                                  • 我们只需要添加Access-Control-Allow-Methods

                                  • res['Access-Control-Allow-Headers'] = '*'
                                    
                                    def core_view(request):
                                        res = HttpResponse("ok")
                                        res['Access-Control-Allow-Origin'] = '*'
                                        if request.method =='OPTIONS':
                                            res['Access-Control-Allow-Headers'] = '*'
                                            res['Access-Control-Allow-Methods'] = '*'
                                        return res
                                    
                                    # 注意注释跨域403
                                    MIDDLEWARE = [
                                        'django.middleware.security.SecurityMiddleware',
                                        'django.contrib.sessions.middleware.SessionMiddleware',
                                        'django.middleware.common.CommonMiddleware',
                                        # 'django.middleware.csrf.CsrfViewMiddleware',
                                        'django.contrib.auth.middleware.AuthenticationMiddleware',
                                        'django.contrib.messages.middleware.MessageMiddleware',
                                        'django.middleware.clickjacking.XFrameOptionsMiddleware',
                                    ]
                                    

                                    Django前后端打通

                                    Django前后端打通

                                    ​ 非简单请求(non-simple requests)在CORS(跨源资源共享)中,指的是不满足简单请求条件的请求。简单请求和非简单请求的区分主要是基于HTTP请求的一些特性,而不仅仅是基于发送了几次请求。

                                    简单请求需要满足以下条件:

                                    1. 请求方法只能是以下几种之一:HEAD、GET、POST。
                                    2. HTTP头信息不超出以下几种字段:
                                      • Accept
                                      • Accept-Language
                                      • Content-Language
                                      • Last-Event-ID
                                      • Content-Type:只限于三个值 application/x-www-form-urlencoded、multipart/form-data、text/plain

                                    ​ 如果HTTP请求不满足以上条件,那么它就是一个非简单请求。

                                    ​ 非简单请求在浏览器发送真正的请求之前,会首先发送一个预检请求(preflight request),请求方法是OPTIONS。预检请求会询问服务器是否允许该跨域请求。服务器响应预检请求时,需要包含一些CORS相关的响应头信息,比如 Access-Control-Allow-Origin、Access-Control-Allow-Methods、Access-Control-Allow-Headers 等,来告知浏览器该跨域请求是否被允许。

                                    ​ 所以,非简单请求并不是看你发送了几次请求,而是看请求的HTTP方法、头信息等是否满足简单请求的条件。如果不满足,浏览器就会发送预检请求,这增加了一次额外的HTTP请求。

                                    【 2 】自定义中间件

                                    • views.py

                                      from rest_framework.views import APIView
                                      from lufy.utils.utils_response import APIResponse 
                                      def core_view(request):
                                          res = HttpResponse("ok")
                                          return res
                                      
                                      • urls.py

                                        from django.urls import path
                                        from . import views
                                        from .views import core_view
                                        urlpatterns = [
                                            # option
                                            path('option/', core_view),
                                        ]
                                        
                                        • 在utils/utils.
                                          ## 中间件###
                                          from django.utils.deprecation import MiddlewareMixin
                                          class CorsMiddleWare(MiddlewareMixin):
                                              def process_response(self,request,response):
                                                  if request.method=="OPTIONS":
                                                      #可以加*
                                                      response["Access-Control-Allow-Headers"]="*"
                                                      response['Access-Control-Allow-Methods'] = '*'
                                                  response["Access-Control-Allow-Origin"] = "*"
                                                  return response
                                          
                                          • 配置文件新的dev.py

                                            MIDDLEWARE = [
                                                'utils.utils_middleware.CorsMiddleWare',
                                            ]
                                            
                                              

                                            首页

                                            {{ res.message }}

                                            import { reactive, onMounted } from 'vue'; import axios from 'axios'; // 使用 reactive 来创建响应式的数据对象 const res = reactive({ message: '' }); // 在 onMounted 生命周期钩子中发送请求 onMounted(async () => { try { const response = await axios.put('http://127.0.0.1:8000/user/option/', { headers: { token: 'asd.fas.sadas' // 在请求头中添加自定义的 token } }); res.message = response.data.message; // 这里可以处理响应的其他数据 console.log(response); } catch (error) { console.error('Error fetching data:', error); // 在这里你可以选择以某种方式通知用户或处理错误 } }); /* 你的样式代码 */

                                            Django前后端打通

                                            【 3 】第三方app解决

                                            # 1、使用pip安装
                                            pip install django-cors-headers
                                            # 2、添加到setting的app中
                                            INSTALLED_APPS = (
                                            	...
                                            	'corsheaders',
                                            	...
                                            )
                                            # 3、添加中间件
                                            MIDDLEWARE = [  
                                            	...
                                            	'corsheaders.middleware.CorsMiddleware',
                                            	...
                                            ]
                                            # 4、setting下面添加下面的配置
                                            CORS_ORIGIN_ALLOW_ALL = True
                                            CORS_ALLOW_METHODS = (
                                            	'DELETE',
                                            	'GET',
                                            	'OPTIONS',
                                            	'PATCH',
                                            	'POST',
                                            	'PUT',
                                            	'VIEW',
                                            )
                                            CORS_ALLOW_HEADERS = (
                                            	'XMLHttpRequest',
                                            	'X_FILENAME',
                                            	'accept-encoding',
                                            	'authorization',
                                            	'content-type',
                                            	'dnt',
                                            	'origin',
                                            	'user-agent',
                                            	'x-csrftoken',
                                            	'x-requested-with',
                                            	'Pragma',
                                            	'token',
                                            )
                                            ### 中间件源码分析
                                            if conf.CORS_ALLOW_ALL_ORIGINS and not conf.CORS_ALLOW_CREDENTIALS:
                                                response[ACCESS_CONTROL_ALLOW_ORIGIN] = "*"
                                            if request.method == "OPTIONS":
                                                        response[ACCESS_CONTROL_ALLOW_HEADERS] = ", ".join(conf.CORS_ALLOW_HEADERS)
                                                        response[ACCESS_CONTROL_ALLOW_METHODS] = ", ".join(conf.CORS_ALLOW_METHODS)
                                            
                                            • 1、使用pip安装

                                              # pip install django-cors-headers
                                              

                                              Django前后端打通

                                            • 2、添加到setting的app中

                                              INSTALLED_APPS = (
                                                	...
                                                	'corsheaders',
                                                	...
                                                )
                                              
                                              • 3、添加中间件

                                                MIDDLEWARE = [  
                                                	...
                                                	'corsheaders.middleware.CorsMiddleware',
                                                	...
                                                ]
                                                
                                              • 4、setting下面添加下面的配置(放在新建的common_settings)

                                                CORS_ORIGIN_ALLOW_ALL = True
                                                CORS_ALLOW_METHODS = (
                                                	'DELETE',
                                                	'GET',
                                                	'OPTIONS',
                                                	'PATCH',
                                                	'POST',
                                                	'PUT',
                                                	'VIEW',
                                                )
                                                CORS_ALLOW_HEADERS = (
                                                	'XMLHttpRequest',
                                                	'X_FILENAME',
                                                	'accept-encoding',
                                                	'authorization',
                                                	'content-type',
                                                	'dnt',
                                                	'origin',
                                                	'user-agent',
                                                	'x-csrftoken',
                                                	'x-requested-with',
                                                	'Pragma',
                                                	'token',
                                                )
                                                

                                                Django前后端打通

VPS购买请点击我

文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

目录[+]