常见跨域解决方案以及Ocelot 跨域配置
常见跨域解决方案以及Ocelot 跨域配置
Intro
我们在使用前后端分离的模式进行开发的时候,如果前端项目和api项目不是一个域名下往往会有跨域问题。今天来介绍一下我们在Ocelot网关配置的跨域。
什么是跨域
跨域:
浏览器对于javascript的同源策略的限制,例如a.cn下面的js不能调用b.cn中的js,对象或数据(因为a.cn和b.cn是不同域),所以跨域就出现了.
上面提到的,同域的概念又是什么呢??? 简单的解释就是相同域名,端口相同,协议相同
同源策略:
请求的url地址,必须与浏览器上的url地址处于同域上,也就是域名,端口,协议相同.
比如:我在本地上的域名是study.cn,请求另外一个域名一段数据

这个时候在浏览器上会报错:

这个就是同源策略的保护,如果浏览器对javascript没有同源策略的保护,那么一些重要的机密网站将会很危险~
study.cn/json/jsonp/jsonp.html
当协议、子域名、主域名、端口号中任意一个不相同时,都算作不同域。不同域之间相互请求资源,就算作“跨域”。
| 请求地址 | 形式 | 结果 |
|---|---|---|
| http://study.cn/test/a.html | 同一域名,不同文件夹 | 成功 |
| http://study.cn/json/jsonp/jsonp.html | 同一域名,统一文件夹 | 成功 |
| http://a.study.cn/json/jsonp/jsonp.html | 不同域名,文件路径相同 | 失败 |
| http://study.cn:8080/json/jsonp/jsonp.html | 同一域名,不同端口 | 失败 |
| https://study.cn/json/jsonp/jsonp.html | 同一域名,不同协议 | 失败 |
跨域几种常见的解决方案
解决跨域问题有几种常见的解决方案:
跨域资源共享(CORS)
通过在服务器端配置 CORS 策略即可,每门语言可能有不同的配置方式,但是从本质上来说,最终都是在需要配置跨域的资源的Response上增加允许跨域的响应头,以实现浏览器跨域资源访问,详细可以参考MDN上的这篇CORS介绍
JSONP
JSONP 方式实际上返回的是一个callbak,通常为了减轻web服务器的负载,我们把js、css,img等静态资源分离到另一台独立域名的服务器上,在html页面中再通过相应的标签从不同域名下加载静态资源,而被浏览器允许,基于此原理,我们可以通过动态创建script,再请求一个带参网址实现跨域通信。
- 原生实现:
<script>
var script = document.createElement('script');
script.type = 'text/javascript';
// 传参一个回调函数名给后端,方便后端返回时执行这个在前端定义的回调函数
script.src = 'http://www.domain2.com:8080/login?user=admin&callback=handleCallback';
document.head.appendChild(script);
// 回调执行函数
function handleCallback(res) {
alert(JSON.stringify(res));
}
</script>
服务端返回如下(返回时即执行全局函数):
handleCallback({"status": true, "user": "admin"})
- jquery ajax:
$.ajax({
url: 'http://www.domain2.com:8080/login',
type: 'get',
dataType: 'jsonp', // 请求方式为jsonp
jsonpCallback: "handleCallback", // 自定义回调函数名
data: {}
});
后端 node.js 代码示例:
var querystring = require('querystring');
var http = require('http');
var server = http.createServer();
server.on('request', function(req, res) {
var params = qs.parse(req.url.split('?')[1]);
var fn = params.callback;
// jsonp返回设置
res.writeHead(200, { 'Content-Type': 'text/javascript' });
res.write(fn + '(' + JSON.stringify(params) + ')');
res.end();
});
server.listen('8080');
console.log('Server is running at port 8080...');
JSONP 只支持 GET 请求
代理
- 前端代理
在现代化的前端开发的时候往往可以配置开发代理服务器,实际作用相当于做了一个请求转发,但实际请求的api地址是没有跨域问题的,然后由实际请求的api服务器转发请求到实际的存在跨域问题的api地址。
angular 配置开发代理可以参考 angular反向代理配置
- 后端代理
后端可以通过一个反向代理如(nginx),统一暴露一个服务地址,然后为所有的请求设置跨域配置,配置 CORS 响应头,Ocelot是ApiGateway,也可以算是api的反向代理,但不仅仅如此。
Ocelot 跨域配置
示例代码:
app.UseOcelot((ocelotBuilder, pipelineConfiguration) =>
{
// This is registered to catch any global exceptions that are not handled
// It also sets the Request Id if anything is set globally
ocelotBuilder.UseExceptionHandlerMiddleware();
// Allow the user to respond with absolutely anything they want.
if (pipelineConfiguration.PreErrorResponderMiddleware != null)
{
ocelotBuilder.Use(pipelineConfiguration.PreErrorResponderMiddleware);
}
// This is registered first so it can catch any errors and issue an appropriate response
ocelotBuilder.UseResponderMiddleware();
ocelotBuilder.UseDownstreamRouteFinderMiddleware();
ocelotBuilder.UseDownstreamRequestInitialiser();
ocelotBuilder.UseRequestIdMiddleware();
ocelotBuilder.UseMiddleware<ClaimsToHeadersMiddleware>();
ocelotBuilder.UseLoadBalancingMiddleware();
ocelotBuilder.UseDownstreamUrlCreatorMiddleware();
ocelotBuilder.UseOutputCacheMiddleware();
ocelotBuilder.UseMiddleware<HttpRequesterMiddleware>();
// cors headers
ocelotBuilder.Use(async (context, next) =>
{
if (!context.DownstreamResponse.Headers.Exists(h => h.Key == HeaderNames.AccessControlAllowOrigin))
{
var allowedOrigins = Configuration.GetAppSetting("AllowedOrigins").SplitArray<string>();
context.DownstreamResponse.Headers.Add(new Header(HeaderNames.AccessControlAllowOrigin, allowedOrigins.Length == 0 ? new[] { "*" } : allowedOrigins));
context.DownstreamResponse.Headers.Add(new Header(HeaderNames.AccessControlAllowHeaders, new[] { "*" }));
context.DownstreamResponse.Headers.Add(new Header(HeaderNames.AccessControlRequestMethod, new[] { "*" }));
}
await next();
});
})
.Wait();
这里扩展了一个 Ocelot pipeline 的配置,这样我们可以直接很方便的直接在 Startup 里配置 Ocelot 的请求管道。
核心代码:
// cors headers
ocelotBuilder.Use(async (context, next) =>
{
if (!context.DownstreamResponse.Headers.Exists(h => h.Key == HeaderNames.AccessControlAllowOrigin))
{
var allowedOrigins = Configuration.GetAppSetting("AllowedOrigins").SplitArray<string>();
context.DownstreamResponse.Headers.Add(new Header(HeaderNames.AccessControlAllowOrigin, allowedOrigins.Length == 0 ? new[] { "*" } : allowedOrigins));
context.DownstreamResponse.Headers.Add(new Header(HeaderNames.AccessControlAllowHeaders, new[] { "*" }));
context.DownstreamResponse.Headers.Add(new Header(HeaderNames.AccessControlRequestMethod, new[] { "*" }));
}
await next();
});
在 HttpRequester 中间件后面添加这个中间件在响应中增加跨域请求头配置,这里先判断了一下下面的api有没有配置,如果已经配置则不再配置,使用下游api的跨域配置,这样一来,只需要在网关配置指定的允许跨域访问的源即使下游api没有设置跨域也是可以访问了
需要说明一下的是如果想要这样配置需要 Ocelot 13.2.0 以上的包,因为之前 HttpRequester 这个中间件没有调用下一个中间件,详见 https://github.com/ThreeMammals/Ocelot/pull/830
Reference
- https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS
- https://segmentfault.com/a/1190000011145364
- https://github.com/ThreeMammals/Ocelot/pull/830
常见跨域解决方案以及Ocelot 跨域配置的更多相关文章
- 浅谈跨域以及WebService对跨域的支持
跨域问题来源于JavaScript的同源策略,即只有 协议+主机名+端口号 (如存在)相同,则允许相互访问.也就是说JavaScript只能访问和操作自己域下的资源,不能访问和操作其他域下的资源. 在 ...
- 浅谈跨域以WebService对跨域的支持
跨域问题来源于JavaScript的同源策略,即只有 协议+主机名+端口号 (如存在)相同,则允许相互访问.也就是说JavaScript只能访问和操作自己域下的资源,不能访问和操作其他域下的资源. 在 ...
- 跨域以及WebService对跨域的支持
无耻收藏该博主的成果啦!https://www.cnblogs.com/yangecnu/p/introduce-cross-domain.html 通过域验证访问WebService:https:/ ...
- 跨域解决方案一:使用CORS实现跨域
跨站HTTP请求(Cross-site HTTP request)是指发起请求的资源所在域不同于请求指向的资源所在域的HTTP请求. 比如说,我在Web网站A(www.a.com)中通过<img ...
- JSON跨域解决方案收集
最近面试问的挺多的一个问题,就是JavaScript的跨域问题.在这里,对跨域的一些方法做个总结.由于浏览器的同源策略,不同域名.不同端口.不同协议都会构成跨域:但在实际的业务中,很多场景需要进行跨域 ...
- js最全的十种跨域解决方案
在客户端编程语言中,如javascript和ActionScript,同源策略是一个很重要的安全理念,它在保证数据的安全性方面有着重要的意义.同 源策略规定跨域之间的脚本是隔离的,一个域的脚本不能访问 ...
- WebApi 跨域解决方案 --CORS
跨站HTTP请求(Cross-site HTTP request)是指发起请求的资源所在域不同于请求指向的资源所在域的HTTP请求. 比如说,我在Web网站A(www.a.com)中通过<img ...
- Ajax跨域解决方案大全
题纲 关于跨域,有N种类型,本文只专注于ajax请求跨域(,ajax跨域只是属于浏览器"同源策略"中的一部分,其它的还有Cookie跨域iframe跨域,LocalStorage跨 ...
- AJAX POST&跨域 解决方案 - CORS
一晃又到新年了,于是开始着手好好整理下自己的文档,顺便把一些自认为有意义的放在博客上,记录成点的点滴. 跨域是我在日常面试中经常会问到的问题,这词在前端界出现的频率不低,主要原因还是 ...
随机推荐
- 递归找到多级文件夹中所有pdf文件的py程序
因个人需要,写了一个可以递归找到多级文件夹中所有pdf的小程序,发布出来供有需要的人参考或使用. import os import re import shutil from os.path impo ...
- 程序员修神之路--redis做分布式锁可能不那么简单
菜菜哥,复联四上映了,要不要一起去看看? 又想骗我电影票,对不对? 呵呵,想去看了叫我呀 看来你工作不饱和呀 哪有,这两天我刚基于redis写了一个分布式锁,很简单 不管你基于什么做分布式锁,你觉得很 ...
- 对python中等值和大小比较
等值.大小比较 在python中,只要两个对象的类型相同,且它们是内置类型(字典除外),那么这两个对象就能进行比较.关键词:内置类型.同类型.所以,两个对象如果类型不同,就没法比较,比如数值类型的数值 ...
- 【C++常用函数】头文件<algorithm>中的常用函数(绝对值,交换,比较)
swap(a,b) 用于交换a,b两个变量的值: max(a,b) 返回a,b中的最大值: min(a,b) 返回a,b中的最小值: abs(x) 返回x的绝对值,x必须是整数:
- kvm2
kvm虚拟机的桥接网络 默认的虚拟机网络是NAT模式,网段192.168.122.0/24 1:创建桥接网卡 创建桥接网卡命令 virsh iface-bridge eth0 br0 取消桥接网卡命令 ...
- SpringCloud(八):springcloud-bus消息总线(刷新配置服务)
Bus消息总线: 好了现在我们接着上一篇的随笔,继续来讲.上一篇我们讲到,我们如果要去更新所有微服务的配置,在不重启的情况下去更新配置,只能依靠spring cloud config了,但是,是我们要 ...
- HTML基础——表单的应用
1.表单的构成 一个完整的表单由表单控件(表单元素).提示信息和表单域3个部分构成. 表单控件:包含了具体的表单功能项,如单行文本输入框.密码输入框.复选框.提交按钮.搜索框等. 提示信息:一个表单中 ...
- Object-C里的类目,延展,协议
1.类目 类目就是为已存在的类添加新的方法.但是不能添加实例变量.比如系统的类,我们看不到他的.m文件,所以没有办法用直接添加方法的方式去实现. @interface NSMutableArray ( ...
- Doxygen程序注释转换说明文档
Doxygen使用 https://www.jianshu.com/p/9464eca6aefe
- Python中机器学习-验证码识别-粗略总结
#验证码识别# 解决办法:将验证码切割成单个字符训练 遇到问题:验证码字符大小不一或重叠 对上述问题的解决:通过CNN(卷积神经网络)直接就是端到端不分割的识别方式 处理验证码:将图片二值化 输入验证 ...