常见跨域解决方案以及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,再请求一个带参网址实现跨域通信。

  1. 原生实现:
 <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"})
  1. 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 请求

代理

  1. 前端代理

在现代化的前端开发的时候往往可以配置开发代理服务器,实际作用相当于做了一个请求转发,但实际请求的api地址是没有跨域问题的,然后由实际请求的api服务器转发请求到实际的存在跨域问题的api地址。

angular 配置开发代理可以参考 angular反向代理配置

  1. 后端代理

后端可以通过一个反向代理如(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

常见跨域解决方案以及Ocelot 跨域配置的更多相关文章

  1. 浅谈跨域以及WebService对跨域的支持

    跨域问题来源于JavaScript的同源策略,即只有 协议+主机名+端口号 (如存在)相同,则允许相互访问.也就是说JavaScript只能访问和操作自己域下的资源,不能访问和操作其他域下的资源. 在 ...

  2. 浅谈跨域以WebService对跨域的支持

    跨域问题来源于JavaScript的同源策略,即只有 协议+主机名+端口号 (如存在)相同,则允许相互访问.也就是说JavaScript只能访问和操作自己域下的资源,不能访问和操作其他域下的资源. 在 ...

  3. 跨域以及WebService对跨域的支持

    无耻收藏该博主的成果啦!https://www.cnblogs.com/yangecnu/p/introduce-cross-domain.html 通过域验证访问WebService:https:/ ...

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

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

  5. JSON跨域解决方案收集

    最近面试问的挺多的一个问题,就是JavaScript的跨域问题.在这里,对跨域的一些方法做个总结.由于浏览器的同源策略,不同域名.不同端口.不同协议都会构成跨域:但在实际的业务中,很多场景需要进行跨域 ...

  6. js最全的十种跨域解决方案

    在客户端编程语言中,如javascript和ActionScript,同源策略是一个很重要的安全理念,它在保证数据的安全性方面有着重要的意义.同 源策略规定跨域之间的脚本是隔离的,一个域的脚本不能访问 ...

  7. WebApi 跨域解决方案 --CORS

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

  8. Ajax跨域解决方案大全

    题纲 关于跨域,有N种类型,本文只专注于ajax请求跨域(,ajax跨域只是属于浏览器"同源策略"中的一部分,其它的还有Cookie跨域iframe跨域,LocalStorage跨 ...

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

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

随机推荐

  1. 关于jQuery MiniUI

    jQuery MiniUI v3.0 jQuery MiniUI - 专业WebUI控件库.它能缩短开发时间,减少代码量,使开发者更专注于业务和服务端,轻松实现界面开发,带来绝佳的用户体验. http ...

  2. RTX5的汽车级,工业级,医疗和铁路安全认证已经通过,证书已颁发

    说明: 1.当前RTX5的教程已经在制作中,使用CMSIS-RTOS V2封装层,含FreeRTOS,配套V7,V6和V5板子​. 2.我们各种开发板和模块的资料汇总贴,搞了个cnblogs,临时先用 ...

  3. 汇编子程序模块化(near&far)

    1: Near 近端使用  C语言实现:  #include <stdio.h>#include <stdlib.h> void print(){ printf("p ...

  4. pip安装插件报错。

    报错: Cannot unpack file C:\Windows\TEMP\pip-unpack-4mbfczpj\simple (downloaded from C:\Windows\TEMP\p ...

  5. Cypress 之 常用API

    .visit() 访问一个远程URL.>>详情参考 Cypress 之 cy.visit() cy.visit(url) cy.visit(url, options) cy.visit(o ...

  6. iOS中点击按钮跳转到外部浏览器和内部打开

    如图所示,需要实现点击一个按钮,跳转到指定网页: -(void)pushBtnCellClickDeleate{ NSLog(@"跳转"); //在APP内部打开指定网页 UIWe ...

  7. Android 列表对话框 使用数组

    添加一个数组 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceSt ...

  8. 剑指offer 25:二叉树中和为某一值的路径

    题目描述 输入一颗二叉树的根节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径.路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径.(注意: 在返回值的list中,数组长度大 ...

  9. ansible 流程控制

    ansible 流程控制 使用when判断主机名 - hosts: rsync_server tasks: - name: Install rsyncd Server yum: name: rsync ...

  10. CodeForces - 1238D(思维)

    题意 https://vjudge.net/problem/CodeForces-1238D 如果一个字符串的每个字母,属于至少一个(长度大于1)的回文串,则称这个字符串为good. 一个长度为n的字 ...