关键词:
原文:常见跨域解决方案以及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
前端常见跨域解决方案(代码片段)
什么是跨域跨域是指一个域下的文档或脚本试图去请求另一个域下的资源,这里跨域是广义的。广义的跨域:资源跳转:A链接、重定向、表单提交资源嵌入:<link>、<script>、<img>、<frame>等dom标签,还有样式中bac... 查看详情
前端常见跨域解决方案(全)(代码片段)
https://segmentfault.com/a/1190000011145364什么是跨域?跨域是指一个域下的文档或脚本试图去请求另一个域下的资源,这里跨域是广义的。广义的跨域:1.)资源跳转:A链接、重定向、表单提交2.)资源嵌入:<link>、<script>、<img&... 查看详情
前端常见跨域解决方案(全)(代码片段)
什么是跨域?跨域是指一个域下的文档或脚本试图去请求另一个域下的资源,这里跨域是广义的。广义的跨域:1.)资源跳转:A链接、重定向、表单提交2.)资源嵌入:<link>、<script>、<img>、<frame>等dom标签,还有样... 查看详情
前端常见跨域解决方案(代码片段)
什么是跨域?跨域是指一个域下的文档或脚本试图去请求另一个域下的资源,这里跨域是广义的。广义的跨域:1.)资源跳转:A链接、重定向、表单提交2.)资源嵌入:<link>、<script>、<img>、<frame>... 查看详情
前端常见跨域解决方案(全)(代码片段)
跨域是指一个域下的文档或脚本试图去请求另一个域下的资源,这里跨域是广义的。广义的跨域:1.)资源跳转:A链接、重定向、表单提交2.)资源嵌入:<link>、<script>、<img>、<frame>等dom标签,还有样式中background:u... 查看详情
前端常见的跨域解决方案(代码片段)
什么是跨域:一个域名下的文档或者脚本试图请求另外一个域名的下的资源广义的跨域:资源跳转:a链接、重定向、表单提交资源嵌入:<link><script> <img>等dom标签脚本请求:js发起的ajax请求,... 查看详情
解决跨域问题以及django中post传递参数错误(代码片段)
一、跨域在进行前后端开发的时候需要涉及到跨域的问题,跨域既可以在前端解决也可以在后端解决。前段解决的思路就是转换路径,将发出的请求的url地址转换成可以映射成的地址。后端的解决思路是将获取的地址转换成可以... 查看详情
ajax基础4--什么是跨域以及如何解决跨域(代码片段)
...策略和jsonp同源策略(⭐⭐⭐)什么是同源什么是同源策略跨域(⭐⭐⭐)什么是跨域浏览器对跨域请求的拦截如何实现跨域数据请求`JSONP`什么是`JSONP`(⭐⭐⭐)`JSONP`的实现原理(⭐⭐⭐)自己实现一个简单的`JSONP`... 查看详情
常见的跨域方法(九种解决办法)(代码片段)
跨域是指一个域下的文档或脚本试图去请求另一个域下的资源,这里跨域是广义的。广义的跨域:资源跳转:A链接、重定向、表单提交资源嵌入:<link>、<script>、<img>、<frame>等dom标签,还有样式中background:url()... 查看详情
什么是跨域,以及解决方案
...sdn.net/weixin_42039396/article/details/80040099前后端分离与跨域的解决方案(CORS的原理)https://blog.csdn.net/cuixiaogang110/article/details/81948173什么是跨域、怎么解决跨域以及如何实现跨域下的登录https://blog.csdn.net/msg1254765721/article/details/90090198 查看详情
egg中通过egg-cors配置服务器端允许跨域以及cookie允许跨域(代码片段)
...。此时,你可能就是遇到跨域问题了,在Egg中的解决方案如下:1.安装插件npmiegg-cors--save2.配置插件//config/plugin.jsexports.cors=enable:true,package:'egg-cors',;3.配置白名单//config/config.default.js//配置安全验证exports.security&... 查看详情
egg中通过egg-cors配置服务器端允许跨域以及cookie允许跨域(代码片段)
...。此时,你可能就是遇到跨域问题了,在Egg中的解决方案如下:1.安装插件npmiegg-cors--save2.配置插件//config/plugin.jsexports.cors=enable:true,package:'egg-cors',;3.配置白名单//config/config.default.js//配置安全验证exports.security&... 查看详情
实习跨域问题(代码片段)
...示用户未登录。后来通过组里前辈的帮忙,排查出是跨域问题(还是自己经验/见识不足),通过公司发布的域名配置要求进行重新配置,得以解决。因为涉及公司项目内容就不提背景以及解决方法。借这个机... 查看详情
跨域:跨域及解决方法(代码片段)
一、什么是跨域广义的跨域包括:资源跳转:超链接<a>跳转、重定向、表单提交资源嵌入:link、ifram、script、img,以及css样式中的background:url()、@font-face()等外链接脚本请求:js的ajax请求、js或DOM中的跨域操作狭义的跨域:... 查看详情
跨域问题成因和解决方案(代码片段)
...m和js对象的跨域操作等常见狭义跨域场景示例:常见跨域解决方案:1、通过jsonp跨域2、document.domain+iframe跨域3、location.hash+iframe4、window.name+iframe跨域5、postMessage跨域6、跨域资源共享(CORS)7、nginx代理跨域8、nodejs中间件代理跨域... 查看详情
解决跨域问题,实例调用百度地图(代码片段)
...的同源是指,域名、协议、端口均为相同。前端常见跨域解决方案(全)当年那些风骚的跨域操作全解跨域请求处理办法不要再问我跨域的问题了九种“姿势”让你彻底解决跨域问题2.如何解决跨域?JSONP: 查看详情
asp.net之实现自定义跨域(代码片段)
...不同域下导致无法直接访问的问题。 针对跨域有多种解决方案常见的有: JSNOP: 可参考Jquery实现,缺点是需要后端支持; Access-Control-Allow-Domain: 不需要前端处理,后端通过配置响应头信息即可实现... 查看详情
vue+elementui+springbootsession丢失解决方案(代码片段)
前后端分离项目 由于端口不一致会出现跨域问题 解决跨域以后又会出现前后端sessionID不一致首先跨域问题 跨域可以在前端配置代理 proxyTable: ‘/‘: //可配置target:‘http://192.168.0.162:8085‘,... 查看详情