Browse Source

feat: 新增H5页面代理抓取接口解决跨域TLS问题

lsc 4 days ago
parent
commit
1a33dab0e6
1 changed files with 79 additions and 0 deletions
  1. 79 0
      pbl.js

+ 79 - 0
pbl.js

@@ -392,6 +392,85 @@ router.route("/download").all(async(req, res, next) => {
     });
 });
 
+// type=73 H5页面代理抓取:平板/低版本浏览器直连S3跨域或TLS失败时,
+// 由后端代抓HTML返回,前端只需跟自家后端同源通信
+// 用法: GET /proxyHtml?url=<encodeURIComponent(目标地址)>
+var PROXY_HTML_WHITELIST = ["ccrb.s3.cn-northwest-1.amazonaws.com.cn"];
+
+router.route("/proxyHtml").all(function(req, res, next) {
+    var json = queryString(req.url);
+    var targetUrl = json["url"];
+
+    if (!targetUrl) {
+        res.status(400).end("Missing url parameter");
+        return;
+    }
+
+    // 白名单校验:防止接口被当万能代理滥用
+    // var allowed = PROXY_HTML_WHITELIST.some(function(domain) {
+    //     return targetUrl.indexOf("https://" + domain + "/") === 0;
+    // });
+    // if (!allowed) {
+    //     res.status(403).end("Domain not allowed");
+    //     return;
+    // }
+
+    var finished = false;
+    var fail = function(status, msg) {
+        if (finished) return;
+        finished = true;
+        res.status(status).end(msg);
+    };
+
+    var fetchHtml = function(url, redirectCount) {
+        if (redirectCount > 3) {
+            fail(502, "Too many redirects");
+            return;
+        }
+
+        var getReq = https.get(url, function(res2) {
+            // 跟随重定向(S3 偶尔会 302)
+            if ([301, 302, 307, 308].indexOf(res2.statusCode) !== -1 && res2.headers.location) {
+                res2.resume(); // 丢弃响应体,释放连接
+                fetchHtml(res2.headers.location, redirectCount + 1);
+                return;
+            }
+
+            if (res2.statusCode !== 200) {
+                res2.resume();
+                fail(502, "Upstream HTTP " + res2.statusCode);
+                return;
+            }
+
+            var chunks = [];
+            var size = 0;
+            res2.on("data", function(chunk) {
+                chunks.push(chunk);
+                size += chunk.length;
+            });
+            res2.on("end", function() {
+                if (finished) return;
+                finished = true;
+                var data = Buffer.concat(chunks, size);
+                res.setHeader("Content-Type", "text/html; charset=utf-8");
+                res.end(data.toString("utf-8"));
+            });
+        });
+
+        getReq.setTimeout(15000, function() {
+            getReq.destroy();
+            fail(504, "Upstream Timeout");
+        });
+
+        getReq.on("error", function(err) {
+            console.error("proxyHtml fetch error:", err);
+            fail(502, "Fetch Error: " + err.message);
+        });
+    };
+
+    fetchHtml(targetUrl, 0);
+});
+
 // 罗湖get
 router.route("/luohugetTeacherInfo").all((req, res, next) => {
     var json = queryString(req.url);