1. cors 介绍

cors 说的是一个机制,其实相当于一个http协议的约定,就是用一段http头部字段来开一扇后门;

当跨域发生时,服务器本身收不到浏览器发的请求(因为被拦截了),现在服务器说我给你一扇门,但是你要符合一定的条件,只要符合条件就能通信。

2. 原理

当后端服务器引入了cors模块之后,前端每次向该服务器请求通信的时候,会在HTTP头部添加一个字段origin,表示请求来源地址;后端对于请求来源origin进行判断,如果符合要求(没有跨域),那么通信就会被建立,请求通过;如果请求来源origin不符合要求,则不会建立连接。使用cors模块解决跨域问题主要工作在于后端。

浏览器本来会拦截跨域请求,但是加了cors这样的相关字段之后,浏览器就不会拦截;(在预请求中拦截)

在HTTP返回字段中,有一个 Access-Control-Allow-Origin 字段表示能放行什么网址的请求,* 表示放行所有请求。

3. cors 解决跨域

express(app.js)

const express = require('express')

const log = console.log.bind(console)
const app = express() // cors 模块用来解决跨域问题,只要声明了 cor,就说明该服务器允许跨域的访问
const cors = require('cors') app.use(cors()) app.get('/helloworld', (request, response) => {
response.send('hello')
}) const main = () => {
let server = app.listen(2300, () => {
let host = server.address().address
let port = server.address().port log(`应用实例,访问地址为 http://${host}:${port}`)
})
} if (require.main === module) {
main()
}

html(crossOriginDemo.html)

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>跨域demo</title>
<style type="text/css">
.ajaxButton {
width: 100px;
height: 50px;
background: blue;
color: #fff;
display: flex;
justify-content: center;
align-items: center;
}
</style>
</head>
<body>
<div class="ajaxButton">发送请求</div>
<script>
const log = console.log.bind(console) const ajax = (method, url, data, headers, callback) => {
let r = new XMLHttpRequest()
r.open(method, url, true) // 设置 headers
Object.entries(headers).forEach(([k, v]) => {
r.setRequestHeader(k, v)
})
r.onreadystatechange = () => {
if (r.readyState === 4) {
callback(r.response)
}
}
if (method === 'POST') {
data = JSON.stringify(data)
}
r.send(data)
} let ele = document.querySelector('.ajaxButton')
ele.addEventListener('click', function () {
let url = 'http://localhost:2300/helloworld'
let method = 'GET'
let data = {}
let headers = {
'Content-Type': 'application/json',
}
ajax(method, url, data, headers, (r) => {
log('cors r is', r)
})
})
</script>
</body>
</html>

运行结果

使用cors 模块确实能够解决跨域问题, 但是这带来了一个问题:

后端框架中如果使用了cors 模块, 那么所有接口都默认地配置了跨域解决方案, 如果现在存在如下需求:

  1. 一部分接口是暴露给浏览器使用的, 需要配置跨域; 一部分接口是给另一台服务器使用的, 不能配置跨域;
  2. 某部分接口只想暴露给特定的origin

此时使用cors 模块已经不能解决问题了, 需要我们手动配置跨域.

4. 自定义HTTP 头部字段解决跨域

有cors 的机制我们可以知道, 跨域问题的关键其实就是在于两个字段, 分别是

  1. request header 的origin 字段
  2. response header 的Access-Control-Allow-Headers 字段

只要在options 请求, 正常请求中这些字段值为合法值, 那么就解决了跨域问题

配置代码如下:

express(app.js)

const express = require('express')

const log = console.log.bind(console)
const app = express() // cors 模块用来解决跨域问题,只要声明了 cor,就说明该服务器允许跨域的访问
// const cors = require('cors') // app.use(cors()) app.get('/helloworld', (request, response) => {
log('触发了该事件')
response.send('hello')
}) app.get('/singlecors', (request, response) => {
response.set('Access-Control-Allow-Origin', '*')
response.send('hello')
}) // 处理 options 请求, 对于我们的例子来说, 不仅需要处理 origin, 还需要处理 headers
app.options('*', (request, response) => {
log('触发了预请求options')
response.set('Access-Control-Allow-Origin', '*')
response.header('Access-Control-Allow-Headers', 'Content-Type')
response.end()
}) const main = () => {
let server = app.listen(2300, () => {
let host = server.address().address
let port = server.address().port log(`应用实例,访问地址为 http://${host}:${port}`)
})
} if (require.main === module) {
main()
}

html(crossOriginDemo.html):

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>跨域demo</title>
<style type="text/css">
.ajaxButton {
width: 100px;
height: 50px;
background: blue;
color: #fff;
display: flex;
justify-content: center;
align-items: center;
}
</style>
</head>
<body>
<div class="ajaxButton">发送请求</div>
<script>
const log = console.log.bind(console) const ajax = (method, url, data, headers, callback) => {
let r = new XMLHttpRequest()
r.open(method, url, true) // 设置 headers
Object.entries(headers).forEach(([k, v]) => {
r.setRequestHeader(k, v)
})
r.onreadystatechange = () => {
if (r.readyState === 4) {
callback(r.response)
}
}
if (method === 'POST') {
data = JSON.stringify(data)
}
r.send(data)
} let ele = document.querySelector('.ajaxButton')
ele.addEventListener('click', function () {
// let url1 = 'http://localhost:2300/helloworld'
let url2 = 'http://localhost:2300/singlecors'
let method = 'GET'
let data = {}
let headers = {
'Content-Type': 'application/json',
}
ajax(method, url, data, headers, (r) => {
log('cors r is', r)
})
})
</script>
</body>
</html>

运行上面代码之后会发现, url1 依旧存在跨域问题, 不能正常访问数据; url2 不存在跨域问题, 能够正常访问数据, 这是因为对于请求来说, 不仅option 请求需要设置Access-Control-Allow-Headers 字段, GET 数据请求也要配置Access-Control-Allow-Headers 字段; 非简单请求是之前会有一个option 请求, 因此需要配置两次.

5. 代码演示

  1. github 地址:https://github.com/ouleWorld/studyDemo/tree/master/codeDevelopDemo/crossOrigin
  2. 拉取整个项目, 然后将expressDemo/app.js 替换为上述app.js 文件; crossOriginDemo.html替换为上述crossOriginDemo.html文件
  3. 运行expressDemo 后端模块
  4. 运行crossOriginDemo.html 文件

5. 参考链接

  1. 跨域资源共享 CORS 详解
  2. 项目地址

跨域解决方案 - 跨域资源共享cors的更多相关文章

  1. 跨域解决方案一:使用CORS实现跨域

    跨站HTTP请求(Cross-site HTTP request)是指发起请求的资源所在域不同于请求指向的资源所在域的HTTP请求. 比如说,我在Web网站A(www.a.com)中通过<img ...

  2. 【PHP】Ajax跨域解决方案 、jsonp、cors

    参考文章: 1.https://blog.csdn.net/u014727260/article/details/72793459 (后台java,实际上差不多) 2. 如何解决ajax跨域传输 数据 ...

  3. 跨域资源共享(CORS)问题解决方案

    CORS:Cross-Origin Resource Sharing(跨域资源共享) CORS被浏览器支持的版本情况如下:Chrome 3+.IE 8+.Firefox 3.5+.Opera 12+. ...

  4. AJAX POST&跨域 解决方案 - CORS

    一晃又到新年了,于是开始着手好好整理下自己的文档,顺便把一些自认为有意义的放在博客上,记录成点的点滴.          跨域是我在日常面试中经常会问到的问题,这词在前端界出现的频率不低,主要原因还是 ...

  5. AJAX POST&跨域 解决方案 - CORS(转载)

    跨域是我在日常面试中经常会问到的问题,这词在前端界出现的频率不低,主要原因还是由于安全限制(同源策略, 即JavaScript或Cookie只能访问同域下的内容),因为我们在日常的项目开发时会不可避免 ...

  6. 跨域资源共享CORS与JSONP

    同源策略限制: 同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果没有同源策略,攻击者可以通过JavaScript获取你的邮件以及其他敏感信息,比如说 ...

  7. (转) AJAX POST&跨域 解决方案 - CORS

    跨域是我在日常面试中经常会问到的问题,这词在前端界出现的频率不低,主要原因还是由于安全限制(同源策略, 即JavaScript或Cookie只能访问同域下的内容),因为我们在日常的项目开发时会不可避免 ...

  8. Atitit.js跨域解决方案attilax大总结 后台java php c#.net的CORS支持

    Atitit.js跨域解决方案attilax大总结 后台java php c#.net的CORS支持 1. 设置 document.domain为一致  推荐1 2. Apache 反向代理 推荐1 ...

  9. 第十四节:Asp.Net Core 中的跨域解决方案(Cors、jsonp改造、chrome配置)

    一. 整体说明 1. 说在前面的话 早在前面的章节中,就详细介绍了.Net FrameWork版本下MVC和WebApi的跨域解决方案,详见:https://www.cnblogs.com/yaope ...

随机推荐

  1. CSS颜色及文本字体

    CSS颜色及文本字体 CSS颜色表示法 CSS文本设置 CSS边框属性 背景属性 元素溢出 CSS颜色及文本字体 CSS颜色表示法 颜色名表示,比如:red 红色,yellow黄色,pick粉色 16 ...

  2. 【华为云技术分享】MongoDB经典故障系列五:sharding集群执行sh.stopBalancer()命令被卡住怎么办?

    [摘要] MongoDB sharding集群执行sh.stopBalancer()命令时被卡住怎么办?别慌,华为云数据库来给您支招,收下这份方案指南,让您分分钟远离被自建MongoDB数据库支配的恐 ...

  3. Altium Designer PCB封装bug,元件焊盘位置偏移解决方法

    1.问题描述:在拖动几个电阻位置时,意外发现Altium designer20版本软件的一个bug——0805的电阻两焊盘位置发生了偏移,如下图所示. 2.解决办法: ①选中焊盘偏移的封装,右键剪切掉 ...

  4. Intellij Idea2018破解教程(激活到2099年)

    1.下载IntelliJ IDEA 2018.1.6 链接:https://pan.baidu.com/s/18ZcKiPp3LU5S-la10r5icw 提取码:ghn0 2.安装IntelliJ ...

  5. 前端面试题-http和https区别

    说一下http和https https的SSL加密是在传输层实现的. (1)http和https的基本概念 http: 超文本传输协议,是互联网上应用最为广泛的一种网络协议,是一个客户端和服务器端请求 ...

  6. 深入理解JS中的对象(三):class 的工作原理

    目录 序言 class 是一个特殊的函数 class 的工作原理 class 继承的原型链关系 参考 1.序言 ECMAScript 2015(ES6) 中引入的 JavaScript 类实质上是 J ...

  7. HTTP及Web核心基础

    1. HTTP服务重要基础 1.1 用户访问网站基本流程 (1)客户端从浏览器输入"www.baidu.com"网站地址,回车后,系统首先会查找系统本地的DNS缓存及hosts文件 ...

  8. 【雕爷学编程】MicroPython动手做(05)——零基础学MaixPy之LCD液晶屏

    配套 2.4寸LCD屏 ST7789驱动器芯片(24P 320X240) ST7789驱动器芯片2.4寸LCD屏(24P 320X240)主要参数 1. 模块名称:液晶显示模块2. 型号:KD024C ...

  9. nodejs上使用sql

    1.首先本地要安装mysql, https://www.mysql.com/downloads/. 2.在node中连接mysql,要安装mysql驱动,也就是npm安装mysql模块:npm i m ...

  10. LSTM的备胎,用卷积处理时间序列——TCN与因果卷积(理论+Python实践)

    什么是TCN TCN全称Temporal Convolutional Network,时序卷积网络,是在2018年提出的一个卷积模型,但是可以用来处理时间序列. 卷积如何处理时间序列 时间序列预测,最 ...