谈谈前后端分离中的跨域问题

瀑布君
• 阅读 8458

在前后端分离开发过程中常常出现下面这样的错误提示:

Access to XMLHttpRequest at 'http://127.0.0.1:8000/apis/users/login/' from origin 'http://127.0.0.1:8080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
HelloWorld.vue?18db:50 err Error: Network Error
    at createError (createError.js?16d0:16)
    at XMLHttpRequest.handleError (xhr.js?ec6c:91)

看到关键字CORSAccess-Control-Allow-Origin 可以判断基本上就是跨域相关的错误了。

不了解的人常常一头雾水,本文咱们就来具体探讨下这种跨域问题,彻底搞懂它,解决它。

什么是跨域?造成跨域的原因?

跨域问题是由浏览器的同源策略引起的,在后端编程语言的Http Client调用中不会存在。同源策略中的同源是说站点的协议域名端口都需要相同。

谈谈前后端分离中的跨域问题

跨域便是请求不同源的站点的一种行为操作。

为了更好的了解跨域,我们先来了解下同源策略。同源策略是一种安全策略,它只允许访问来自同一站点的资源。同源策略又分为两种:

  • DOM 同源策略:禁止对不同源页面DOM进行操作;
  • XMLHttpRequest同源策略:禁止使用XHR对象对不同源的服务地址发起HTTP请求;

DOM同源策略,常常发生在iframe的使用中,iframe 中如果嵌套了不同源的页面便会发生跨域。iframe跨域和XHR同源策略造成的跨域解决方法一样。

XMLHttpRequest同源策略便是引起文章开头跨域问题的主要原因。当浏览器请求后端不同源的数据时,会向后端发起一个XHR的HTTP请求,浏览器和后端服务沟通,若没有跨域相关配置,则触发XHR同源策略限制,抛出异常。

XMLHttpRequest(简称XHR)对象用于与服务器交互。通过 XMLHttpRequest 可以在不刷新页面的情况下请求特定 URL,获取数据。除了浏览器的地址栏,浏览器和后端交互(通常是javascripts控制)都是通过XHR对象,在浏览器的console中可以看到XHR的请求。
谈谈前后端分离中的跨域问题

作为用户,同源策略是浏览器对我们上网行为的一种保护。作为开发者,在web开发中确实会用到夸域来获取资源的情况。如何解决呢?下面总结几种常用的跨域解决方法。

常用的解决方法

这里以vue作为前端、Django 作为后端举例说明。

详细完整代码可见:https://github.com/pylixm/django-cross-origin-demo

跨域资源共享(CORS)

CORS(Cross-origin resource sharing,跨域资源共享)是一个 W3C 标准,定义了在必须访问跨域资源时,浏览器与服务器应该如何沟通。它的核心思想,使用自定义的HTTP头部信息让浏览器和后端进行沟通,来决定是否允许跨域请求。

CORS 方式解决跨域,主要需要后端支持,主流浏览器均已支持。站点在访问跨域资源的时候,浏览器会自动的添加HTTP头信息,自动完成与后端的沟通,用户无感知。

下面以vue+django项目说下如何实现。例如在前端我们有个登录的POST请求,我们使用axios直接跨域请求后端接口。如下:

  handleClick(){
  this.$axios.post("http://127.0.0.1:8000/apis/users/login/", {
    username: this.username,
    password: this.password,
  }).then(res=>{
      console.log('res',res)
    }).catch(err=>{
      console.log('err',err)
    })
  },

前端服务端口为8080,后端服务为8000。两个服务的端口不一致,发生了跨域。

Access to XMLHttpRequest at 'http://127.0.0.1:8000/apis/users/login/' from origin 'http://127.0.0.1:8080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
HelloWorld.vue?18db:50 err Error: Network Error
    at createError (createError.js?16d0:16)
    at XMLHttpRequest.handleError (xhr.js?ec6c:91)

Django 可通过第三方的跨域库django-cors-headers添加支持。我们pip install django-cors-headers 并增加如下配置:

INSTALLED_APPS = [
    ... 
    'corsheaders',
    'django_demo.apps.SiteCenterConfig',
]
MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',
    ...
]

# 跨域支持
CORS_ALLOWED_ORIGINS = ['http://127.0.0.1:8080']  # 授权进行跨站点 HTTP 请求的源列表

# 因为跨域之后需要传递sessionid 到浏览器cookie,所以添加如下配置。
CORS_ALLOW_CREDENTIALS = True  # 允许 Cookie 包含在跨站点 HTTP 请求中
SESSION_COOKIE_SAMESITE = None  # django 自己的安全策略

前端增加携带cookie的参数,不需要cookie时,可不用设置:

  handleClick(){
  this.$axios.post("http://127.0.0.1:8000/apis/users/login/", {
    username: this.username,
    password: this.password,
  }
  ,{
    withCredentials:true  // 携带和设置cookie 
  }
  ).then(res=>{
      console.log('res',res)
    }).catch(err=>{
      console.log('err',err)
    })
  },

重启服务,再次访问前端,成功登录。

使用代理解决

使用代理解决,vue框架自带了代理转发,在vue配置文件中增加如下配置解决:

    proxyTable: {
      // 这里就是代理了
      '/apis': {
        target: 'http://127.0.0.1:8000/apis/',   //设置你调用的接口域名和端口号 别忘了加http,就是后台服务地址
        changeOrigin: true,
        pathRewrite: {
          '^/apis': ''
        }
      }
    },

在生产环境中,还可以使用Nignx作为代理来解决跨域问题。

以上两种方式,便是前后端分离中最常用的跨域解决方案了,除了这两种方案,还有如下几种:

  • jsonp
  • location.hash 跨域
  • postMessage 跨域
  • window.name 跨域
  • document.domain 跨域

这些都不常用,文本暂不讨论。

总结

至此,在前后端分离中,跨域问题及解决方案便讨论完了。跨域问题,不了解的朋友会一头雾水,了解之后解决便可信手拈来。针对 vue+django 架构中的两种解决方案,使用一种即可解决跨域。在使用CORS方案时,携带Cookie时,注意增加相关配置。其他后端框架大都有成熟的组件支持,与django配置参数类似,大家可触类旁通。

参考

谈谈前后端分离中的跨域问题

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
美凌格栋栋酱 美凌格栋栋酱
6个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
待兔 待兔
2年前
什么是跨域以及如何解决?通俗易懂带你彻底搞定
什么是跨域以及如何解决?通俗易懂带你彻底搞定现在的web项目,很多都是前后端分离,特别容易出现跨域问题那么什么是跨域问题呢?本篇文章带你彻底从本质上弄明白什么是跨域问题以及如何解决一跨域有什么现象?我们先看一下
Wesley13 Wesley13
3年前
java将前端的json数组字符串转换为列表
记录下在前端通过ajax提交了一个json数组的字符串,在后端如何转换为列表。前端数据转化与请求varcontracts{id:'1',name:'yanggb合同1'},{id:'2',name:'yanggb合同2'},{id:'3',name:'yang
Easter79 Easter79
3年前
springboot的跨域
https://www.cnblogs.com/520playboy/p/7306008.html1、对于前后端分离的项目来说,如果前端项目与后端项目部署在两个不同的域下,那么势必会引起跨域问题的出现。针对跨域问题,我们可能第一个想到的解决方案就是jsonp,并且以前处理跨域问题我基本也是这么处理。但是jsonp方式也同样有不足,不管是对
Easter79 Easter79
3年前
springboot2之优雅处理返回值
前言最近项目组有个老项目要进行前后端分离改造,应前端同学的要求,其后端提供的返回值格式需形如{"status":0,"message":"success","data":{}}方便前端数据处理。要实现前端同学这个需求,其实也挺简单的,
Stella981 Stella981
3年前
Node接入层可视化逻辑编排,还可以这样做?
背景:Node前后端分离带来的变化2016年跨境供应链体验技术部经历了从JavawebxMVC技术架构演进到Node前后端分离的技术架构。前后端分离优势前后端分离以后,Node服务端扮演了web接入层的角色,起到了web端和Java微服务端的桥梁作用,从架构层解决了以下问题:1.VM层前后端
Stella981 Stella981
3年前
No 'Access
跨域说明前后端分离下,跨域已是一个老生常谈的话题,但很多小伙伴还是经常面临这样的问题,且解决方案多变多样。这里介绍一种简单直接的后端解决方案。解决跨域(服务端)/CorsConfig跨域@authorylyue@since2018年11
Easter79 Easter79
3年前
SpringBoot解决跨域问题
在开发前后端分离的项目时,常常会碰到跨域请求的问题。这是因为浏览器的安全性限制,不允许Ajax访问协议不同、域名不同、端口号不同的数据接口,否则会出报No'AccessControlAllowOrigin'headerispresentontherequestedresource错误。SpringBoot通过设置cors(跨源
Stella981 Stella981
3年前
AJAX学习笔记(五、AJAX+JSON与Servlet前后端交互)
前后端分离实现前后端分离的好处就不用多说了,前后端那么JavaWeb项目前后端分离是怎么实现的呢?1.浏览器发送请求2.直接到达html页面(前端控制路由与渲染页面,整个项目开发的权重前移)3.html页面负责调用服务端接口产生数据(通过ajax等等,后台返回json格式数据,json数据格式因为简洁高效而取代xml)
Stella981 Stella981
3年前
SpringBoot解决跨域问题
在开发前后端分离的项目时,常常会碰到跨域请求的问题。这是因为浏览器的安全性限制,不允许Ajax访问协议不同、域名不同、端口号不同的数据接口,否则会出报No'AccessControlAllowOrigin'headerispresentontherequestedresource错误。SpringBoot通过设置cors(跨源