跨域

什么是跨域

比如一个链接:http://www.baidu.com(端口默认是80端口),

如果再来一个链接是这样:http://api.baidu.com,这个就算是跨域了(因为域名不同)

再来一个:https://www.baidu.com,这个也是跨域了(因为协议不同,用的https)

再来一个http://www.baidu.com:8888,这个也算跨域,端口号不同

举个实际的例子:

  • API接口数据部署在baidu.com上;
  • Ajax文件部署在cnblogs.com上,Ajax文件会向API (baidu.com) 发送请求,返回数据;
  • 用户通过bing.com访问cnblogs.com的Ajax文件,请求数据

以上过程就发生了跨域访问。如果直接使用Ajax来请求就会失败,就像Chrome提示的:

No 'Access-Control-Allow-Origin' header is present on the requested resource.

 

跨域直白点就是,请求协议,域名(IP),端口号,三个其中任何一个不同都算跨域

CORS

CORS(跨域资源共享,Cross-Origin Resource Sharing)是一种跨域访问的机制,可以让Ajax实现跨域访问

那么如果跨域是什么样的呢?比如,我这里有个restframework项目作为服务器,项目名为drfversion,测试的app名叫testapp,url如下:

view:

启动项目,直接访问这个API接口测试:

在django的templates目录下新建一个test.html,简单的建立了一个vue和axios的项目,作为前端的异步请求,写入以下参数:

点那个谷歌浏览器图标,然后直接谷歌浏览器打开,这里这个功能是pycharm给我们提供的功能,此时这个作为客户端,访问:

里面的这个参数提示就是跨域了,浏览器默认有个同源策略,他检测到这个http://localhost:63342的url与我们后端启动的DRF项目url:http://127.0.0.1:8000/test/不同源,也就是跨域了,所以报错。

再看接口,看其实后端没有错误,已经给我们返回了数据:

所以跨域请求的根本原因是浏览器的同源策略造成的,要解决这个跨域请求就可以在这方面研究了

而跨域分简单请求和复杂请求

简单请求

HTTP方法是只能是HEAD, GET和POST

HTTP头信息不超出以下几种字段:

  • Accept
  • Accept-Language
  • Content-Language
  • Last-Event-ID
  • Content-Type

而且Content-Type只能是下列类型:

  • application/x-www-from-urlencoded
  • multipart/form-data
  • text/plain

复杂请求

除了简单请求的都是复杂请求了,所以如果传输json数据,Content-Type类型就是json了,所以一定是复杂请求了

复杂请求会先发出一个预请求,又叫预检,OPTIONS请求

常见的解决跨域的方法

1.协议和域名,端口都是用同一个就行

2.利用jsonp解决跨域问题

因为看代码相信你也看到了,那个script脚本标签导入的两个js文件,一个用的vue,一个用的axios,然后用到的是各自的cdn,url也都不一样:

其实也算跨域了,但是浏览器并没有给我们拦截,所以我们是否也可以直接用script的src属性来访问,当然可以:

刷新刚才那个前端客户端页面,发现真的可以这样

那么再大胆一点,发一个函数名怎么样?然后前端先定义好这个函数名,试试看:

后端的视图函数里返回这个函数调用的字符串:

前端访问,可行,确实打印了

但是,这只能做GET啊,如果做POST,PUT啥的请求呢?就没办法了,而且在调用函数时,前端和后端必须商量好函数名,必须统一才行,所以这jsonp还是有很大的弊端的

2.修改Django中的views.py文件

修改views.py中对应API的实现函数,允许其他域通过Ajax请求数据:

def myview(_request):

    response = HttpResponse(json.dumps({"key": "value", "key2": "value"}))

    response["Access-Control-Allow-Origin"] = "*"

    response["Access-Control-Allow-Methods"] = "POST, GET, OPTIONS"

    response["Access-Control-Max-Age"] = "1000"

    response["Access-Control-Allow-Headers"] = "*"

    return response

  

4.在后端做处理——Python是利用django中间件添加响应头

GET:

现在什么都不做,只是get请求,再看下提示的是什么:

注意这句话:No 'Access-Control-Allow-Origin' header is present on the requested resource.

好,在后端写一个中间件:

配置文件里应用上:

重启项目,前端再次访问,这次终于没有红色的报错了

POST:

再来个POST请求看看:

后端的view:

其他后端代码不变,前端访问,又变红了

注意这句话:Request header field Content-Type is not allowed by Access-Control-Allow-Headers in preflight response.

好的中间件做如下修改:

重启访问,有了:

OPTIONS(PUT,DELETE):

好如果是put或者delete请求呢?这个按前面说的简单请求与复杂请求的说法,这两个请求方式肯定是复杂请求了,即那个OPTIONS了,搞一个put的请求看看,还是先看看它报什么错:

view:

重启访问,报错提示的字段跟前面的POST请求字段好像是一个说法对吧

但是我们只加了post的,并没加put或者delete的,修改中间件:

重启访问,确实已解决

然后,其实中间件还是稍微优化一下,把简单请求和复杂请求做个判断处理,复杂请求可以预检嘛,节省下资源:

重启访问,没有任何问题:

相关代码:

中间件middle:

from django.utils.deprecation import MiddlewareMixin

class CorsMiddle(MiddlewareMixin):
    def process_response(self, request, response):
        response['Access-Control-Allow-Origin'] = '*'
        if request.method == 'OPTIONS':
            response['Access-Control-Allow-Headers'] = 'Content-Type'
            response['Access-Control-Allow-Methods'] = 'PUT,DELETE'
        return response

view:

from rest_framework.views import APIView
from rest_framework.views import Response
class TestView(APIView):
    def get(self, request):
        return Response('跨域测试')

    def post(self, request):
        return Response('post接口测试')

    def put(self,request):
        return Response('put请求测试')   ....(还有个delete请求就省略了,跟put请求一样的)

settings:

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',
    'middle.CorsMiddle',
]

前端代码test.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>test</title>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    <script>
    //    function PrintTest() {
    //        console.log('jsonp test');
    //    }
    </script>

    <script src="http://127.0.0.1:8000/test/"></script>
</head>
<body>
<div id="app"></div>
<script>
    const app = new Vue({
        el: '#app',
        mounted() {
            axios.request({
                url: 'http://127.0.0.1:8000/test/',
                method: 'GET',// "POST","PUT","DELETE"
                //data:{
                //    "name":"jack",
                //}
            }).then(function (data) {
                console.log(data)
            })
        }
    })
</script>
</body>
</html>

以上4个方法,已经可以解决大部分的跨域请求问题,但是由于我后期再次遇到过更强大的问题:以上4个方法针对火狐浏览器没法,火狐浏览器安全性比较高,一样会报跨域请求,即使你在django的中间件添加了response处理

下面这个使用第三方库django-cors-headers的方法就可以完美解决火狐浏览器问题

5.使用第三方库django-cors-headers

在Django中,有人开发了CORS-header的middleware,github:传送门

只需在settings.py中做一些简单的配置即可,其他不用作任何修改,我们也不用自己手动的创建中间件对response处理了,直接用以下配置即可,  现在用起来服务器端完全开放,开启CORS,没有任何跨域烦恼

安装django-cors-headers:

pip install django-cors-headers

  

在settings.py中增加:

INSTALLED_APPS = (

  ...

  'corsheaders',

  ...

) 

...

MIDDLEWARE_CLASSES = (

  ...

  'corsheaders.middleware.CorsMiddleware',  # 注意顺序,必须放在Comon前面

  'django.middleware.common.CommonMiddleware',

  ...

)

#以下直接赋值放在settings.py里即可解决

CORS_ALLOW_CREDENTIALS = True

CORS_ORIGIN_ALLOW_ALL = True

CORS_ORIGIN_WHITELIST = ( '*' )

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',

)

  

总结:

  • 针对跨域请求,其实本质上是浏览器对返回的结果response的拦截
  • 最常见的解决办法就是在后端返回结果response时做数据处理,让浏览器不拦截
  • 大杀招使用django-cors-headers库,秒杀一切,简直6得不行

前后端分离djangorestframework——解决跨域请求的更多相关文章

  1. springboot 前后端分离开发解决跨域访问

    最近新学习了Java EE开发框架springboot,我在使用springboot前后台分离开发的过程中遇到了跨域求问题.在网上寻找答案的过程中发现网上的解决方案大多比较零散,我在这里整理一个解决方 ...

  2. 前后端分离开发,跨域时jsessionid每次请求都变化的问题解决方法

    本解决方法的使用前提是,前端开发使用的是vue,后端使用java(SpringMVC) 在前后端分离开发过程中,可能会出现因跨域而导致每次请求的jsessionid不一致的情况 解决方法: 前端:要在 ...

  3. 解决vue+springboot前后端分离项目,前端跨域访问sessionID不一致导致的session为null问题

    问题: 前端跨域访问后端接口, 在浏览器的安全策略下默认是不携带cookie的, 所以每次请求都开启了一次新的会话. 在后台打印sessionID我们会发现, 每次请求的sessionID都是不同的, ...

  4. 前后端分离 vue+springboot 跨域 session+cookie失效问题

    环境: 前端 vue   ip地址:192.168.1.205 后端 springboot2.0  ip地址:192.168.1.217 主要开发后端. 问题: 首先登陆成功时将用户存在session ...

  5. 前后端分离crud(跨域问题)讲解

    1 前后端分离 1.1 后端 ssm+maven 多模块 swagger 文档描述(代码拷贝过来,就可以生成了,https://www.cnblogs.com/wings-xh/p/11991511. ...

  6. 【坑】前后端分离开发中 跨域问题以及前台不带cookie的问题

    文章目录 前言 跨域问题 cookie问题 拦截器导致的跨域问题 后记 前言 场景一: 前台哒哒哒的点击页面,发送请求,但是后台服务器总是没有回应,后台接口虽打了断点,但是根本进不到断点处: 前端:我 ...

  7. 前后端分离产生的跨域问题的解决方案之--jsonp、nginx代理、设置头信息等

    前言 在前后端没有分离的时候,前端开发要么是写静态页面,数据渲染后端来做,要么就是前端的页面和后端的代码刚开始的时候就合并在一起,每次后端代码更新了之后,前端也要更新一下代码,然后重启一下服务,还是比 ...

  8. Vue+SpringBoot前后端分离中的跨域问题

    在前后端分离开发中,需要前端调用后端api并进行内容显示,如果前后端开发都在一台主机上,则会由于浏览器的同源策略限制,出现跨域问题(协议.域名.端口号不同等),导致不能正常调用api接口,给开发带来不 ...

  9. 前后端分离下的跨域CAS请求

    最重要的两点: ajax请求跨域的时候,默认不会携带cookie. 请求分为普通请求(HttpRequest)和Ajax请求(XMLHttpRequest) 先屡一下跨域CAS认证的流程: 前端发起a ...

随机推荐

  1. 并发编程(五)——AbstractQueuedSynchronizer 之 ReentrantLock源码分析

    本文将从 ReentrantLock 的公平锁源码出发,分析下 AbstractQueuedSynchronizer 这个类是怎么工作的,希望能给大家提供一些简单的帮助. AQS 结构 先来看看 AQ ...

  2. Python爬虫入门教程 39-100 天津市科技计划项目成果库数据抓取 scrapy

    爬前叨叨 缘由 今天本来没有打算抓取这个网站的,无意中看到某个微信群有人问了一嘴这个网站,想看一下有什么特别复杂的地方,一顿操作下来,发现这个网站除了卡慢,经常自己宕机以外,好像还真没有什么特殊的.. ...

  3. 一条命令解决mac版本python IDLE无法输入中文问题

    安装完Python通常自动就有了一个简易的集成环境IDLE,但在mac上,无法在IDLE中使用中文. 通常故障有两种情况: 在IDLE中,中文输入法根本无法工作,不会弹出输入框,所有的输入都被当做英文 ...

  4. dotnet core高吞吐Http api服务组件FastHttpApi

    简介 是dotNet core下基于Beetlex实现的一个高度精简化和高吞吐的HTTP API服务开源组件,它并没有完全实现HTTP SERVER的所有功能,而是只实现了在APP和WEB中提供数据服 ...

  5. Chapter 4 Invitations——27

    "Myself, obviously." He enunciated every syllable, as if he were talking to someone mental ...

  6. 15分钟在阿里云Kubernetes服务上快速建立Jenkins X Platform并运用GitOps管理应用发布

    本文主要介绍如何在阿里云容器服务Kubernetes上快速安装部署Jenkins X Platform并结合demo实践演示GitOps的操作流程. 注意:本文中使用的jx工具.cloud-envir ...

  7. 为容器化的 Go 程序搭建 CI

    本文介绍如何使用 Jenkins 的声明式 pipeline 为一个简单的 Golang web 应用搭建 CI 环境.如果你还不太了解 Jenkins 及其声明式 pipeline,请先参考笔者的 ...

  8. 聊天框Demo:DotNetCore+ActiveMQ+Mqttjs 实现前后台消息监听

    网上查了查 ActiveMQ + .net core 的例子很少,自己做一个demo 作为记录,另外FineUI Core基础版要来了,出来后我会用FineUI再做一版,为知识星球的引流... 1.安 ...

  9. k8s架构分析(二)--技术流ken

    master节点 k8s的集群由master和node组成,节点上运行着若干k8s服务. master节点之上运行着的后台服务有kube-apiserver .kube-scheduler.kube- ...

  10. 第31章 日志 - Identity Server 4 中文文档(v1.0.0)

    IdentityServer使用ASP.NET Core提供的标准日志记录工具.Microsoft文档有一个很好的介绍和内置日志记录提供程序的描述. 我们大致遵循Microsoft使用日志级别的指导原 ...