好记性不如 烂笔头,趁热记录下,给未来的自己

0 | 前言

项目需求永远是学习技术最好的动力

项目中,有这样一个事务场景,作为一个平台,能够布置用户写的各种运用,比方gradio运用,streamlit运用,也能够嵌入外部网站的url,这些运用在平台上经过嵌入 iframe 去展现。

然后,针对外部网站,有许多临时性的 demo,或许开发者不方便装备网站 https 证书的时分,往往供给的都是依据 http 协议的拜访 url,假如父页面是依据 https 的话,在其嵌入 http 协议的 iframe 链接,就会报错而无法拜访。

那么,面对这样的场景,咱们该怎么去完成呢?

1 | 思路

其实顶层 workaround 的思路便是两个方向,怎么做,能够:

  1. 在 https 的 iframe 里支持 http 的拜访?
  2. 把 http 的拜访转化成 https 的?

第一个方向,调研了几天,各种搜索,问GPT,得到的结论是:不行,原因如下:

  1. 混合内容问题:当一个安全的 HTTPS 页面试图加载非安全的 HTTP 内容时,这种情况被称为“混合内容”。浏览器通常会阻挠这种行为,由于它降低了整个页面的安全性。
  2. 安全危险:HTTP 内容没有加密,易受中间人进犯。假如在 HTTPS 页面中加载 HTTP 内容,进犯者或许利用这个未加密的内容来进犯整个页面,比方经过注入恶意脚本。
  3. 隐私和完整性:HTTPS 旨在维护用户数据的隐私和完整性。混合内容使得 HTTPS 页面的这些保障部分失效,由于嵌入的 HTTP 内容不受相同的维护。
  4. 用户信赖:用户或许信赖一个安全的 HTTPS 页面,假如这个页面包括不安全的内容,这或许误导用户,使他们对整个页面的安全性有错误的了解。

调转方向,研究第二个思路。其实,此刻问题能够进一步细化:任意给定一个 http 的链接,怎么用 https 来拜访?

自然而然,面对和 url 相关的需求,首要想到的便是 nginx 署理(什么,想不到?!那就多看看烂笔头的文章:》)。大概思路如下:

  1. 建立一个 nginx 署理服务;
  2. 供给一个依据 https 的 url,nginx 接收到恳求 url;
  3. 编写 lua 脚本,完成对恳求 url 解析,生成原始的 http 恳求 url;
  4. 运用 proxy_pass 将 https 的恳求转发给 原始的 http 地址。

需求留意的是,这种计划需求有个前置条件,具有泛域名证书。泛域名证书要钱?来看看这篇文章,请求一个免费的~《网站要上 HTTPS 却没有 SSL/TLS 证书?| 教你一招搞定免费的(泛域名)SSL/TLS 证书》

2 | 实战

2.1 转化规则

要完成https url 转 http url,首要需求设置转化规则。咱们知道,url 是由 协议+域名+端口 组成的,比方:

能够看到,一个 url 里会包括字母、数字、符号等等,那么能够设置转化规则如下:

  1. 数字/字母 -> 数字/字母
  2. 符号 -> {符号英文},比方 . -> _dot_, : -> _colon_
  3. 实在 url 转化后的字符串作为 base url 的二级子域名

假定 base url 为 abc.com,那么 http://192.168.0.1:6443 这个 http url 就能够转化为:
192_dot_168_dot_0_dot_1_colon_6443.abc.com

2.2 nginx 要害装备

首要,经过ngx.re.match找出二级子域名,

然后,将值赋给ngx.var.service,

接着,履行proxy办法,在proxy办法里,运用lua的string.gsub函数对字符串做替换操作,生成实在的拜访url,

最终,利用proxy_pass 将恳求转发出去。

这儿展现核心代码:

server {
    listen 80;
    location / {
      set $service  '';
      set $type '';
      rewrite_by_lua '
        local host = ngx.var.host
        local m = ngx.re.match(host, "(.+).abc.com")
        ngx.var.service = m[1]
        ngx.exec("@proxy")
      ';
    }
    location @proxy {
      access_by_lua_block {
        local req_service = ngx.var.service
        local real_service = string.gsub(req_service, "_dot_", ".")
        real_service = string.gsub(real_service, "_slash_", "/")
        real_service = string.gsub(real_service, "_colon_", ":")
        ngx.var.service = real_service
      }
      proxy_pass http://$service;
    }
}

需求留意的是,这儿仅仅最核心的部分代码,还有一些必要的nginx装备(比方加头,支持ws协议等等),需求依据事务需求定制化去添加和修改。

以上。