您当前的位置:首页 > 电脑百科 > 程序开发 > 编程百科

使用cors完成跨域请求处理

时间:2020-08-10 16:01:54  来源:  作者:

跨域的含义

同源策略以及其限制内容

同源策略是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。所谓 同源是指"协议+域名+端口" 三者相同,即便两个不同的域名指向同一个ip地址,也非同源。

使用cors完成跨域请求处理

 

同源策略限制内容有:

  • Cookie、LocalStorage、IndexedDB 等存储性内容
  • DOM 节点
  • AJAX 请求不能发送

但是有三个标签允许跨域加载资源:

<img src="...">
<link href="...">
<scripts src="...">

常见跨域场景

当协议、子域名、主域名、端口号中任意一个不相同时,都算作不同域。不同域之间相互请求资源,就算作“跨域”。常见跨域场景如下图所示:

使用cors完成跨域请求处理

 

特别说明两点:

第一:如果是协议和端口造成的跨域问题“前端”是处理不了的。

第二:在跨域问题上,仅仅是通过“URL的首部”来识别而不会根据域名对应的IP地址是否相同来判断。“URL的首部”可以理解为“协议, 域名和端口必须匹配”。

这里你或许有个疑问: 请求跨域了,那么请求到底发出去没有?

跨域并不是请求发不出去,请求能发出去,服务端能收到请求并正常返回响应,只是响应被浏览器拦截了。你可能会疑问明明通过表单的方式可以发起跨域请求,为什么 Ajax 就不行?因为归根结底,跨域是为了阻止用户读取到另一个域名下的内容,Ajax 可以获取响应,浏览器认为这不安全,所以拦截了响应。但是表单并不会获取新的内容,所以可以发起跨域请求。同时也说明了 跨域并不能完全阻止 CSRF ,因为请求毕竟是发出去了。

实现跨域的方式之一:CORS

  • CORS 全称是 跨域资源共享(Cross-Origin Resource Sharing) ,是一种 AJAX 跨域请求资源的方式,支持现代浏览器,IE支持10以上。
  • CORS与JSONP的使用目的相同,但是比JSONP更强大。 JSONP只支持GET请求,CORS支持所有类型的HTTP请求 。JSONP的优势在于支持老式浏览器,以及可以向不支持CORS的网站请求数据。
  • 浏览器会自动进行 CORS 通信,实现 CORS 通信的关键是后端。只要后端实现了 CORS,就实现了跨域。
  • 服务端设置 Access-Control-Allow-Origin 就可以开启 CORS。 该属性表示 哪些域名可以访问资源,如果设置通配符(*)则表示所有网站都可以访问资源 。response = HttpResponse('向非同源的网址返回其请求所对应的响应数据') response["Access-Control-Allow-origin"] = "*"

前端发送请求类型

虽然设置 CORS 和前端没什么关系,但是通过这种方式解决跨域问题的话,会在发送请求时出现两种情况,分别为 简单请求 和 复杂请求 。

简单请求

只要同时满足以下两大条件,就属于简单请求

条件1:使用下列方法之一:

  • GET
  • HEAD
  • POST

条件2:Content-Type 的值仅限于下列三者之一:

  • text/plain
  • multipart/form-data
  • Application/x-www-form-urlencoded

请求中的任意 XMLHttpRequestUpload 对象均没有注册任何事件监听器; XMLHttpRequestUpload 对象可以使用 XMLHttpRequest.upload 属性访问。

复杂请求

不符合以上条件的请求就是复杂请求。

复杂请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求,该请求是 option 方法的,通过该请求来知道服务端是否允许跨域请求。

我们用 PUT 向后台请求时,属于复杂请求,后台需做如下配置:

// 允许哪个方法访问我
res.setHeader('Access-Control-Allow-Methods', 'PUT')
// 预检的存活时间
res.setHeader('Access-Control-Max-Age', 6)
// OPTIONS请求不做任何处理
if (req.method === 'OPTIONS') {
  res.end() 
}
// 定义后台返回的内容
app.put('/getData', function(req, res) {
  console.log(req.headers)
  res.end('****')
})

接下来我们看下一个完整复杂请求的例子,并且介绍下CORS请求相关的字段

// index.html
let xhr = new XMLHttpRequest()
document.cookie = 'name=xiamen' // cookie不能跨域
xhr.withCredentials = true // 前端设置是否带cookie
xhr.open('PUT', 'http://localhost:4000/getData', true)
xhr.setRequestHeader('name', 'xiamen')
xhr.onreadystatechange = function() {
  if (xhr.readyState === 4) {
    if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
      console.log(xhr.response)
      //得到响应头,后台需设置Access-Control-Expose-Headers
      console.log(xhr.getResponseHeader('name'))
    }
  }
}
xhr.send()
//server1.js
let express = require('express');
let app = express();
app.use(express.static(__dirname));
app.listen(3000);
//server2.js
let express = require('express')
let app = express()
let whitList = ['http://localhost:3000'] //设置白名单
app.use(function(req, res, next) {
  let origin = req.headers.origin
  if (whitList.includes(origin)) {
    // 设置哪个源可以访问我
    res.setHeader('Access-Control-Allow-Origin', origin)
    // 允许携带哪个头访问我
    res.setHeader('Access-Control-Allow-Headers', 'name')
    // 允许哪个方法访问我
    res.setHeader('Access-Control-Allow-Methods', 'PUT')
    // 允许携带cookie
    res.setHeader('Access-Control-Allow-Credentials', true)
    // 预检的存活时间
    res.setHeader('Access-Control-Max-Age', 6)
    // 允许返回的头
    res.setHeader('Access-Control-Expose-Headers', 'name')
    if (req.method === 'OPTIONS') {
      res.end() // OPTIONS请求不做任何处理
    }
  }
  next()
})
app.put('/getData', function(req, res) {
  console.log(req.headers)
  res.setHeader('name', 'jw') //返回一个响应头,后台需设置
  res.end('****')
})
app.get('/getData', function(req, res) {
  console.log(req.headers)
  res.end('****')
})
app.use(express.static(__dirname))
app.listen(4000)

上述代码由 http://localhost:3000/index.html 向 http://localhost:4000/ 跨域请求,正如我们上面所说的,后端是实现 CORS 通信的关键。

应用django-cors-headers

drf后端+vue前端的项目

在做以drf框架作为后端支撑以及以vue前端框架作为页面展示的前后端分离的web项目中,前端会向后端请求数据,也会涉及到非同源跨域的问题,以下操作将做详细处理

# vue前端域名
www.aliang.cn

# drf后端域名
api.aliang.com

修改vue项目的配置信息

  • 通过浏览器访问前端vue项目,会出现Nginx的欢迎页面,主要因为我们当前操作中已经有一个nginx监听了80端口,所以访问 www.aliang.cn 网址时,会自动被转发到127.0.0.1本机,因为没有网址默认端口是80端口,所以被nginx进行处理了当前请求,因此我们暂时先把nginx关闭。
# 查找nginx的进程
ps -ef|grep nginx
# 关闭进程
sudo kill -9 nginx进程号
  • 修改vue项目的配置文件config/index.js
host: 'www.aliang.cn', // can be overwritten by process.env.HOST
    port: 8080, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
    autoOpenBrowser: true,
  • 保存修改信息,并重启项目
  • 通过浏览器访问drf项目,会出现以下错误信息You may need to add 'api.aliang.com' to ALLOWED_HOSTS
  • 可以通过设置drf项目中的配置文件, settings/dev.py的ALLOWED_HOSTS ,设置允许访问
# 设置哪些客户端可以通过地址访问到后端
ALLOWED_HOSTS = [
    'api.aliang.cn',
]
  • 现在,前端与后端分处不同的域名,我们需要为后端添加跨域访问的支持否则前端使用axIOS则无法请求到后端提供的api数据,故使用CORS来解决后端对跨域访问的支持。

使用django-cors-headers扩展

  • 安装
pip install django-cors-headers -i https://pypi.douban.com/simple/
  • drf后端项目配置文件中添加应用
INSTALLED_APPS = (
    ...
    'corsheaders',
    ...
)
  • drf后端项目配置文件中设置中间件【必须写在第一个位置】
MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',
    ...
]
  • drf后端项目配置文件中添加白名单
# CORS组的配置信息
CORS_ORIGIN_WHITELIST = (
    'www.aliang.cn:8080',
)
CORS_ALLOW_CREDENTIALS = True  # 允许ajax跨域请求时携带cookie

完成了上面的步骤,我们就可以通过后端提供数据给前端使用ajax访问了。

  • 前端使用 axios就可以访问到后端提供给的数据接口,但是如果要附带cookie信息,前端还要设置一下。需要注意的是,如果要发送Cookie, Access-Control-Allow-Origin 就不能设为星号,必须指定明确的、与请求网页一致的域名。同时,Cookie依然遵循同源政策,只有用服务器域名设置的Cookie才会上传,其他域名的Cookie并不会上传,且(跨源)原网页代码中的 document.cookie 也无法读取服务器域名下的Cookie。
  • 前端引入axios插件并配置允许axios发送cookie信息[axios本身也不允许ajax发送cookie到后端]
npm i axios -S
  • 在main.js中引用 axios插件
import axios from 'axios'; // 从node_modules目录中导入包
// 允许ajax发送请求时附带cookie
axios.defaults.withCredentials = true;

Vue.prototype.$axios = axios; // 把对象挂载vue中

如果你拷贝前端vue-cli项目到咱们指定目录下,如果运行起来有问题,一些不知名的错误,那么就删除node_modules文件件,然后在项目目录下执行 npm install 这个指令,重新按照package.json文件夹中的包进行node_modules里面包的下载

原文作者:阿良

原文链接:https://www.cnblogs.com/fengting0913/p/13451489.html



Tags:跨域请求   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
跨域的含义同源策略以及其限制内容同源策略是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。所谓 同源是指"协议+域名+...【详细内容】
2020-08-10  Tags: 跨域请求  点击:(61)  评论:(0)  加入收藏
PHP在做接口的时候,前端调用接口可能会提示跨域请求,那么可以通过以下两种方法解决:1、前端发送jsonp 请求2、后端可以在接口输出的地方添加如下代码header(&#39;Content-Type:...【详细内容】
2019-08-12  Tags: 跨域请求  点击:(978)  评论:(0)  加入收藏
▌简易百科推荐
摘 要 (OF作品展示)OF之前介绍了用python实现数据可视化、数据分析及一些小项目,但基本都是后端的知识。想要做一个好看的可视化大屏,我们还要学一些前端的知识(vue),网上有很多比...【详细内容】
2021-12-27  项目与数据管理    Tags:Vue   点击:(1)  评论:(0)  加入收藏
程序是如何被执行的&emsp;&emsp;程序是如何被执行的?许多开发者可能也没法回答这个问题,大多数人更注重的是如何编写程序,却不会太注意编写好的程序是如何被运行,这并不是一个好...【详细内容】
2021-12-23  IT学习日记    Tags:程序   点击:(9)  评论:(0)  加入收藏
阅读收获✔️1. 了解单点登录实现原理✔️2. 掌握快速使用xxl-sso接入单点登录功能一、早期的多系统登录解决方案 单系统登录解决方案的核心是cookie,cookie携带会话id在浏览器...【详细内容】
2021-12-23  程序yuan    Tags:单点登录(   点击:(8)  评论:(0)  加入收藏
下载Eclipse RCP IDE如果你电脑上还没有安装Eclipse,那么请到这里下载对应版本的软件进行安装。具体的安装步骤就不在这赘述了。创建第一个标准Eclipse RCP应用(总共分为六步)1...【详细内容】
2021-12-22  阿福ChrisYuan    Tags:RCP应用   点击:(7)  评论:(0)  加入收藏
今天想简单聊一聊 Token 的 Value Capture,就是币的价值问题。首先说明啊,这个话题包含的内容非常之光,Token 的经济学设计也可以包含诸多问题,所以几乎不可能把这个问题说的清...【详细内容】
2021-12-21  唐少华TSH    Tags:Token   点击:(9)  评论:(0)  加入收藏
实现效果:假如有10条数据,分组展示,默认在当前页面展示4个,点击换一批,从第5个开始继续展示,到最后一组,再重新返回到第一组 data() { return { qList: [], //处理后...【详细内容】
2021-12-17  Mason程    Tags:VUE   点击:(14)  评论:(0)  加入收藏
什么是性能调优?(what) 为什么需要性能调优?(why) 什么时候需要性能调优?(when) 什么地方需要性能调优?(where) 什么时候来进行性能调优?(who) 怎么样进行性能调优?(How) 硬件配...【详细内容】
2021-12-16  软件测试小p    Tags:性能调优   点击:(19)  评论:(0)  加入收藏
Tasker 是一款适用于 Android 设备的高级自动化应用,它可以通过脚本让重复性的操作自动运行,提高效率。 不知道从哪里听说的抖音 app 会导致 OLED 屏幕烧屏。于是就现学现卖,自...【详细内容】
2021-12-15  ITBang    Tags:抖音防烧屏   点击:(23)  评论:(0)  加入收藏
11 月 23 日,Rust Moderation Team(审核团队)在 GitHub 上发布了辞职公告,即刻生效。根据公告,审核团队集体辞职是为了抗议 Rust 核心团队(Core team)在执行社区行为准则和标准上...【详细内容】
2021-12-15  InfoQ    Tags:Rust   点击:(24)  评论:(0)  加入收藏
一个项目的大部分API,测试用例在参数和参数值等信息会有很多相似的地方。我们可以复制API,复制用例来快速生成,然后做细微调整既可以满足我们的测试需求1.复制API:在菜单发布单...【详细内容】
2021-12-14  AutoMeter    Tags:AutoMeter   点击:(20)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条