V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
GrapeCityChina
V2EX  ›  推广

无需 CORS,用 nginx 解决跨域问题,轻松实现低代码开发的前后端分离

  •  
  •   GrapeCityChina · 2022-07-15 15:19:04 +08:00 · 750 次点击
    这是一个创建于 868 天前的主题,其中的信息可能已经有所发展或是发生改变。

    近年来,前后端分离已经成为中大型软件项目开发的最佳实践。

    在技术层面,前后端分离指在同一个 Web 系统中,前端服务器和后端服务器采用不同的技术栈,利用标准的 WebAPI 完成协同工作。这种前后端分离的"混合开发"模式下,前后端通常会部署到不同的服务器上,即便部署在同一台机器,因为宿主程序(如后端用 Tomcat ,前端用 nginx )不同,端口号也很难统一。

    (图片来源网络)

    这意味着位于 A 域(如https://foo:80/website) 的页面,需要调用 B 域的 WebAPI (如https://bar:8080/webservice),这是一个典型的跨域访问,浏览器默认会判定该操作有安全风险。如果不进行处理,则会拒绝这次 WebAPI 调用,提示对应的错误。

    (跨域请求导致的错误)

    现在如何该怎么解决跨域的问题呢?目前有 4 个主流技术方案:

    JSONP

    如果你需要处理的请求只有 GET ,可以考虑 JSONP 。

    JSONP 的原理就是利用<script>标签没有跨域限制的特点,通过<script>标签 src 属性,发送带有 callback 参数的 GET 请求,服务端将接口返回数据拼凑到 callback 函数中,返回给浏览器,浏览器解析执行,从而前端拿到 callback 函数返回的数据。

    ( JSONP 的调用流程)

    这种做法很常规,但是你需要为前端提供 JSONP 的响应,其他终端调用时提供不带 JSONP 的响应,因此会带来额外的开发和测试工作量。

    iFrame

    通常情况下,前后端分离带来的跨域访问都局限在同一个主域的不同子域(如 a.foo.comb.foo.com )之间。所以,你可以利用 iFrame 加载位于被调用 WebAPI 所在域的页面,然后将两个页面的 document.domain 设置为主域名(如 foo.com ),就通过 iFrame 中的子页面请求 WebAPI 了。

    (图片来源网络)

    这种做法比较麻烦,我们需要为 WebAPI 配套开发起中转作用的页面,但对于开发者而言依旧有很大的开发工作量。

    CORS

    和前两种方案相比,CORS (跨域资源共享)是一个"一劳永逸"的方案。

    我们不需要为每个 WebAPI 做额外的处理,而是需要在后端程序启动时,增加一些处理工作。主流的后端服务都有处理 CORS 的类库,这里就不再做展开介绍了。

    这个方案的核心原理,是在发起正式的请求前,先发送一个 OPTIONS 谓词的 HTTP 请求,询问发起请求的页面是否有调用该域服务的权限;如果后端说 OK ,浏览器就继续请求,否则提示错误。

    使用这种方案的开发工作量小,如果直接使用成熟类库的话,开发和测试的工作量甚至可以忽略不计。不过,因为每个跨域的请求都会触发一次往外的 OPTIONS 请求,对服务器会造成额外的开销和压力。

    反向代理

    反向代理机制,把前端的 A 域和后端的 B 域合并成一个 C 域,从根本上解决跨域问题。

    这个方案仅需配置,对前后端的程序没有侵入;同时内网中的反向代理通常也不会带来额外的性能开销。

    (图片来源网络)

    总体来说在编码开发的时代,上述四种方案都有适用的应用场景,各有优缺点。进入低代码开发时代后,前后端分离的应用面更广,如使用 JavaScript 编码开发前端、配合低代码构建的后端,或使用 Java 编码开发后端,供低代码构建的前端调用。

    (低代码时代的前后端分离,来自 低代码沙龙)

    低代码开发的核心价值在于节省开发投入,提升开发效率,所以,方案 1 ( JSONP )和方案 2 ( iFrame )已经很少被用到低代码混合开发领域。相比于方案 3 ( CORS ),方案 4 (反向代理)因为性能开销较小,应用场景会更多一些。

    下面,我们将以活字格+nginx 为例,介绍利用 nginx 解决跨域问题,实现前后端分离的具体做法。

    (反向代理的架构示意图)

    利用 nginx 解决跨域问题

    1. 开始配置之前,我们使用活字格开发两个应用,仅包含前端页面的 frontend 和包含后端 WebAPI (服务端命令)的 backend ,并将其分别发布到物理机或云主机上,应用的端口设置为 8081 和 8080 。我们可以通过以下地址访问这两个应用:
    1. 安装 nginx ,并在配置文件 /conf/nginx.conf 中 HTTP 节点配置前后端的服务器,即 upstream 节点:
    
    upstream backend {
    
    server host\_name:8080;
    
    }
    
    upstream frontend {
    
    server host\_name\_2:8081;
    
    }
    
    
    1. 在 HTTP 节点下的 server 节点,配置监听端口和转发策略,这样就可以将 http://host_name:8080/backend 映射为 http://proxy_name:8000/backend ,http://host_name_2:8081/frontend 映射为http://proxy_name:8000/frontend
    
    listen 8000;
    
    server\_name proxy\_name;
    
    location /frontend {
    
    proxy\_pass http://frontend/frontend ;
    
    }
    
    location /backend {
    
    proxy\_pass http://backend/backend ;
    
    }
    
    
    1. 上述操作后,用户访问的域名统一成了http://proxy_name:8000,跨域问题解决了。但是,不要着急。活字格默认会启用 Http Referer 验证机制,不允许跨域调用内置服务。所以,你还需要打开前端应用所在的服务端的管理控制台http://host_name_2:22345/UserService/ManagementPage/WebSecurity

    在 HTTP Referrer 允许列表中添加 nginx 代理服务器的地址(也就是用户实际使用的地址,记得在后面加一个*号适配)。

    1. 配置完成后,你可以就可以在前端页面中通过 [发送 HTTP 请求命令] ,调用后端的 WebAPI 了。

    (在前端调用后端 WebAPI 并弹窗显示返回结果)

    特别提示:如果你需要将前端、后端和 nginx 部署在同一台机器上,可以将上述 proxy_name 、host_name 、host_name_2 统一替换为你的机器名或 IP 地址。

    作为一款强大的反向代理和 Web 服务器,nginx 的用途非常广泛,本文仅仅使用到了它的反向代理功能。除此之外对于负载均衡的解决 nginx 也有很优秀的表现,在后续内容中我们会为大家做更加深入的介绍。

    如需详细了解如何使用低代码开发前后端分离的企业级应用,快速转型全栈工程师,可以查看:

    https://gcdn.grapecity.com.cn/forum.php?mod=viewthread&tid=146511&extra=page%3D1%26filter%3Dtypeid%26typeid%3D272

    除此之外如果你对更多低代码行业现状与发展趋势感兴趣可以查看:

    https://help.grapecity.com.cn/pages/viewpage.action?pageId=67969931

    xieqiqiang00
        1
    xieqiqiang00  
       2022-07-15 17:57:19 +08:00
    这和 low code 有什么关系?看的我一头问号
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2239 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 22ms · UTC 00:51 · PVG 08:51 · LAX 16:51 · JFK 19:51
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.