跨域解决方案 - 跨域资源共享cors
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 模块, 那么所有接口都默认地配置了跨域解决方案, 如果现在存在如下需求:
- 一部分接口是暴露给浏览器使用的, 需要配置跨域; 一部分接口是给另一台服务器使用的, 不能配置跨域;
- 某部分接口只想暴露给特定的origin
此时使用cors 模块已经不能解决问题了, 需要我们手动配置跨域.
4. 自定义HTTP 头部字段解决跨域
有cors 的机制我们可以知道, 跨域问题的关键其实就是在于两个字段, 分别是
- request header 的origin 字段
- 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. 代码演示
- github 地址:https://github.com/ouleWorld/studyDemo/tree/master/codeDevelopDemo/crossOrigin
- 拉取整个项目, 然后将expressDemo/app.js 替换为上述app.js 文件; crossOriginDemo.html替换为上述crossOriginDemo.html文件
- 运行expressDemo 后端模块
- 运行crossOriginDemo.html 文件
5. 参考链接
跨域解决方案 - 跨域资源共享cors的更多相关文章
- 跨域解决方案一:使用CORS实现跨域
跨站HTTP请求(Cross-site HTTP request)是指发起请求的资源所在域不同于请求指向的资源所在域的HTTP请求. 比如说,我在Web网站A(www.a.com)中通过<img ...
- 【PHP】Ajax跨域解决方案 、jsonp、cors
参考文章: 1.https://blog.csdn.net/u014727260/article/details/72793459 (后台java,实际上差不多) 2. 如何解决ajax跨域传输 数据 ...
- 跨域资源共享(CORS)问题解决方案
CORS:Cross-Origin Resource Sharing(跨域资源共享) CORS被浏览器支持的版本情况如下:Chrome 3+.IE 8+.Firefox 3.5+.Opera 12+. ...
- AJAX POST&跨域 解决方案 - CORS
一晃又到新年了,于是开始着手好好整理下自己的文档,顺便把一些自认为有意义的放在博客上,记录成点的点滴. 跨域是我在日常面试中经常会问到的问题,这词在前端界出现的频率不低,主要原因还是 ...
- AJAX POST&跨域 解决方案 - CORS(转载)
跨域是我在日常面试中经常会问到的问题,这词在前端界出现的频率不低,主要原因还是由于安全限制(同源策略, 即JavaScript或Cookie只能访问同域下的内容),因为我们在日常的项目开发时会不可避免 ...
- 跨域资源共享CORS与JSONP
同源策略限制: 同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果没有同源策略,攻击者可以通过JavaScript获取你的邮件以及其他敏感信息,比如说 ...
- (转) AJAX POST&跨域 解决方案 - CORS
跨域是我在日常面试中经常会问到的问题,这词在前端界出现的频率不低,主要原因还是由于安全限制(同源策略, 即JavaScript或Cookie只能访问同域下的内容),因为我们在日常的项目开发时会不可避免 ...
- Atitit.js跨域解决方案attilax大总结 后台java php c#.net的CORS支持
Atitit.js跨域解决方案attilax大总结 后台java php c#.net的CORS支持 1. 设置 document.domain为一致 推荐1 2. Apache 反向代理 推荐1 ...
- 第十四节:Asp.Net Core 中的跨域解决方案(Cors、jsonp改造、chrome配置)
一. 整体说明 1. 说在前面的话 早在前面的章节中,就详细介绍了.Net FrameWork版本下MVC和WebApi的跨域解决方案,详见:https://www.cnblogs.com/yaope ...
随机推荐
- C# 数据操作系列 - 2. ADO.NET操作
0.前言 在上一篇中初略的介绍了一下SQL的基本写法,这一篇开始我们正式步入C#操作数据库的范围.通过这一系列的内容,我想大家能对于数据库交互有了一定的认识和基础.闲话不多说,先给大家介绍一个C#操作 ...
- STM32 使用IQmath实现SVPWM
IQMATH TI的片子很香,做的也很好,但是成本相对ST会更高,电机控制方面,TI无疑是做的最好的方案之一,另外TI针对没有浮点运算器的定点DSP推出了IQMATH库,在使用Q格式对数据进行分析和处 ...
- nginx脚本自动安装
nginx脚本自动安装 脚本功能: 自动安装nginx 自动判别系统是否安装nginx 自定义安装nginx路径 自定义安装nginx版本. #!/bin/bash #2019年10月30日16:00 ...
- [hdu5266]区间LCA
题意:给一棵树,求节点L,L+1,...R的最近公共祖先 思路:先对树dfs一下,从根1出发,经过每条边时记录一下终点和到达这个点的时间截,令r[u]表示到达u这个节点的最早时间截,t[x]表示在时间 ...
- vue render 中遇到的问题
以后遇到问题会持续更新 1 render中 判断是否显示 2 render中 属性可以通过判断的形式显示
- vue + typescript,定义全局变量或者方法
众所周知,在 vue中,如果想定义一个全局变量的方法很简单,直接在 vue的原型上挂载属性或者方法即可. 但是,加上了typescript之后, Vue.prototype.$xxx = xxx 这 ...
- python3.x 基础一:str字符串方法
*字符串不能更改值 数据类型字符串str | capitalize(...) 返回字符串中第一个字母大写 | S.capitalize() -> str | | ...
- fastDFS多线程并发执行出现的问题
--------------------- 原作者:Java高级开发 来源:CSDN 原文:https://blog.csdn.net/hang1995/article/details/7924 ...
- Netty 中的消息解析和编解码器
本篇内容主要梳理一下 Netty 中编解码器的逻辑和编解码器在 Netty 整个链路中的位置. 前面我们在分析 ChannelPipeline 的时候说到入站和出站事件的处理都在 pipeline 中 ...
- PAT 乙级-1025 链表反转
给定一个常数K以及一个单链表L,请编写程序将L中每K个结点反转.例如:给定L为1→2→3→4→5→6,K为3,则输出应该为3→2→1→6→5→4:如果K为4,则输出应该为4→3→2→1→5→6,即最后 ...