<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta charset="utf-8" /> <meta name="referrer" content="never"> <title>JavaScript 请求服务负载均衡,仿 nginx upstream</title> </head> <body> <h4>请打开控制台或按F12</h4> <button id="btn1">可用的源</button> <button id="btn2">最快的源</button> <button id="btn3">自定义超时</button> <button id="btn4">获取天气</button> <div id="result"></div> </body> </html>
#result{ color:#fff; overflow: auto; margin-top: 30px; max-height: 300px; background-color: #333; padding: 0 15px; }
/* upstream: From nginx upstream Source must support cross-domain v1.0.1 by netnr 2021-01-15 */ (function (window) { var ups = function (hosts, callback, timeout) { //全局对象、默认请求超时、默认源过期 var gk = "upstreamCache", dto = 3000, es = 30000; if (!(gk in window)) { try { window[gk] = JSON.parse(localStorage.getItem(gk)) || {}; } catch (e) { window[gk] = {} } } var startTime = new Date().valueOf(), cacheKey = hosts.join(','), hostsCache = window[gk][cacheKey]; if (hostsCache && hostsCache.ok.length && startTime - hostsCache.date < es) { callback(hostsCache.ok[0], hostsCache.ok, true); } else { var ok = [], bad = 0, i = 0, len = hosts.length; for (; i < len;) { var host = hosts[i++]; //自动补齐链接 host = host.trim().toLowerCase().indexOf("//") >= 0 ? host : "//" + host; //发起fetch,添加成功的url(该url与hosts可能不一样),须支持跨域请求 fetch(host).then(function (res) { res.ok ? ok.push(res.url) : bad++; }).catch(() => bad++) } var si = setInterval(function () { var isc = false, now = new Date().valueOf(); //当timeout为1,返回最快可用的host if (timeout == 1 && ok.length > 0) { isc = true; } //所有请求结束 或 超时,返回结果 var istimeout = now - startTime > ((timeout == 1 || !timeout) ? dto : timeout); if (ok.length + bad == len || istimeout) { isc = true; } if (isc) { clearInterval(si); window[gk][cacheKey] = { date: now, ok: ok }; localStorage.setItem(gk, JSON.stringify(window[gk])); callback(ok[0], ok, false); } }, 1) } } window.upstream = ups; return ups; })(window); //示例 var hosts = ["cors.eu.org", "api.github.com"]; document.getElementById("btn1").onclick = function () { upstream(hosts, function (fast, ok) { console.log(fast, ok) log(fast, ok) }); } document.getElementById("btn2").onclick = function () { upstream(hosts, function (fast, ok) { console.log(fast, ok) log(fast, ok) }, 1); } document.getElementById("btn3").onclick = function () { upstream(hosts, function (fast, ok) { console.log(fast, ok) log(fast, ok) }, 280); } document.getElementById("btn4").onclick = function () { upstream(["https://cors.eu.org/", "https://netnr.zme.ink/api/v1/Proxy?url="], function (fast) { var api = "http://wthrcdn.etouch.cn/weather_mini?citykey=101040100"; var url = fast + api; fetch(url).then(res => res.json()).then(function (data) { console.log(data); log(data); }); }, 1); } function log() { var ret = document.getElementById("result"); for (var i = 0; i < arguments.length; i++) { var msg = arguments[i]; if (typeof msg != "string") { msg = JSON.stringify(msg); } var pre = document.createElement("pre"); pre.innerHTML = msg; ret.appendChild(pre); } ret.appendChild(document.createElement("hr")) ret.scrollTo(0, 9999999); }