HTTP重定向至HTTPS

自动将HTTP重定向为HTTPS

  1. // ==UserScript==
  2. // @name HTTP重定向至HTTPS
  3. // @name:en Redirect HTTP to HTTPS
  4. // @namespace https://greasyfork.org/zh-CN/users/1257285-dreamprostudio
  5. // @version 2.0
  6. // @description 自动将HTTP重定向为HTTPS
  7. // @description:en Automatically redirect HTTP to HTTPS
  8. // @author DreamProStudio
  9. // @match *://*/*
  10. // @grant GM_registerMenuCommand
  11. // @run-at document-start
  12. // @license GPL-3.0-or-later
  13. // @homepageURL http://www.coolapk.com/u/28432077
  14. // @supportURL https://greasyfork.org/zh-CN/users/1257285-dreamprostudio
  15. // @icon https://pic.imgdb.cn/item/668adf52d9c307b7e9cb7122.png
  16. // ==/UserScript==
  17.  
  18. (function () {
  19. 'use strict';
  20.  
  21. // 常量定义
  22. const CACHE_NAME = 'httpsSupportCache';
  23. const DISABLED_DOMAINS = 'disabledHttpsRedirectDomains';
  24. const HTTP_PROTOCOL = 'http:';
  25. const HTTPS_PROTOCOL = 'https:';
  26. const CACHE_EXPIRY = 7 * 24 * 60 * 60 * 1000; // 7天的缓存过期时间
  27.  
  28. // 变量初始化
  29. let cache = JSON.parse(localStorage.getItem(CACHE_NAME)) || {}; // 从本地存储中获取缓存数据
  30. let disabledDomains = JSON.parse(localStorage.getItem(DISABLED_DOMAINS)) || {}; // 从本地存储中获取禁用域名列表
  31.  
  32. // 语言文本定义
  33. const lang = navigator.language || navigator.userLanguage;
  34. const isChinese = lang.startsWith('zh');
  35. const TEXTS = {
  36. clearCache: isChinese ? '清除HTTPS缓存' : 'Clear HTTPS Cache',
  37. disableRedirect: isChinese ? '禁用当前域名重定向' : 'Disable Redirect for Current Domain',
  38. enableRedirect: isChinese ? '启用当前域名重定向' : 'Enable Redirect for Current Domain',
  39. cacheCleared: isChinese ? '缓存已清除' : 'Cache has been cleared',
  40. redirectDisabled: isChinese ? '重定向已禁用' : 'Redirect has been disabled',
  41. redirectEnabled: isChinese ? '重定向已启用' : 'Redirect has been enabled'
  42. };
  43.  
  44. /**
  45. * 更新缓存
  46. * @param {string} host - 主机名
  47. * @param {boolean} supportsHttps - 是否支持HTTPS
  48. */
  49. function updateCache(host, supportsHttps) {
  50. cache[host] = { supportsHttps, timestamp: Date.now() };
  51. localStorage.setItem(CACHE_NAME, JSON.stringify(cache));
  52. }
  53.  
  54. /**
  55. * 检查主机是否支持HTTPS
  56. * @param {string} host - 主机名
  57. * @returns {Promise<boolean>} - 支持HTTPS返回true,不支持返回false
  58. */
  59. function checkHttpsSupport(host) {
  60. return fetch(`${HTTPS_PROTOCOL}//${host}`, { method: 'HEAD' })
  61. .then(response => response.ok)
  62. .catch(() => false);
  63. }
  64.  
  65. /**
  66. * 检查缓存是否过期
  67. * @param {string} host - 主机名
  68. * @returns {boolean} - 过期返回true,否则返回false
  69. */
  70. function isCacheExpired(host) {
  71. if (!cache[host]) return true;
  72. return (Date.now() - cache[host].timestamp) > CACHE_EXPIRY;
  73. }
  74.  
  75. /**
  76. * 将HTTP重定向至HTTPS
  77. */
  78. function redirectHttpToHttps() {
  79. const host = window.location.hostname;
  80.  
  81. if (disabledDomains[host]) return;
  82.  
  83. if (window.location.protocol === HTTP_PROTOCOL) {
  84. if (cache[host] && !isCacheExpired(host)) {
  85. if (cache[host].supportsHttps) {
  86. window.location.replace(`${HTTPS_PROTOCOL}:${window.location.href.substring(5)}`);
  87. }
  88. return;
  89. }
  90.  
  91. const httpsURL = `${HTTPS_PROTOCOL}:${window.location.href.substring(5)}`;
  92.  
  93. checkHttpsSupport(host).then(supportsHttps => {
  94. updateCache(host, supportsHttps);
  95. if (supportsHttps) {
  96. window.location.replace(httpsURL);
  97. }
  98. });
  99. }
  100. }
  101.  
  102. /**
  103. * 清除过期缓存
  104. */
  105. function clearExpiredCache() {
  106. const now = Date.now();
  107. for (const host in cache) {
  108. if ((now - cache[host].timestamp) > CACHE_EXPIRY) {
  109. delete cache[host];
  110. }
  111. }
  112. localStorage.setItem(CACHE_NAME, JSON.stringify(cache));
  113. }
  114.  
  115. /**
  116. * 更新用户脚本菜单命令
  117. */
  118. function updateMenuCommands() {
  119. GM_registerMenuCommand(TEXTS.clearCache, () => {
  120. clearExpiredCache(); // 只清除过期的缓存
  121. alert(TEXTS.cacheCleared);
  122. });
  123.  
  124. const host = window.location.hostname;
  125. const isDisabled = disabledDomains[host];
  126.  
  127. GM_registerMenuCommand(isDisabled ? TEXTS.enableRedirect : TEXTS.disableRedirect, () => {
  128. if (isDisabled) {
  129. delete disabledDomains[host];
  130. } else {
  131. disabledDomains[host] = true;
  132. }
  133. localStorage.setItem(DISABLED_DOMAINS, JSON.stringify(disabledDomains));
  134. alert(isDisabled ? TEXTS.redirectEnabled : TEXTS.redirectDisabled);
  135. location.reload();
  136. });
  137. }
  138.  
  139. // 清除过期缓存
  140. clearExpiredCache();
  141.  
  142. // 执行HTTP到HTTPS的重定向逻辑
  143. redirectHttpToHttps();
  144.  
  145. // 注册和更新用户脚本菜单命令
  146. updateMenuCommands();
  147.  
  148. })();