如何在Deno Oak中实现HTTP强制重定向至HTTPS?
解决Deno Oak服务器HTTP转HTTPS重定向及握手失败问题
问题本质
当你设置secure: true启动Oak应用时,该端口仅会接受HTTPS请求。此时HTTP请求通过IPTABLES转发到这个端口后,服务器会尝试进行TLS握手,但HTTP请求不携带TLS握手所需信息,直接触发握手失败错误——你的httpRedirect中间件根本没有执行机会,因为连接在握手阶段就已中断。
解决方案
要实现HTTP到HTTPS的重定向,需要让Oak同时监听两个独立端口:一个端口专门处理HTTP请求并执行重定向,另一个端口处理HTTPS业务请求。
修改后的完整代码
import { Application, Router, Context } from 'https://deno.land/x/oak@v10.5.1/mod.ts'; // 配置参数 const HOST = ''; const HTTPS_PORT = '7700'; const HTTP_PORT = '7701'; const CERT_FILE = '/fullchain.pem'; const KEY_FILE = '/privkey.pem'; // 业务路由(HTTPS专用) const router = new Router(); router.get('/', async (ctx) => await respondWith(ctx, './index.html')); // HTTPS应用实例 const httpsApp = new Application(); httpsApp.use(router.routes()); httpsApp.use(router.allowedMethods()); // HTTP应用实例(仅处理重定向) const httpApp = new Application(); httpApp.use(async (ctx: Context) => { // 构造HTTPS地址 const httpsUrl = new URL(ctx.request.url); httpsUrl.protocol = 'https:'; // 若域名通过IPTABLES映射443到7700,可直接去掉port,让浏览器用默认443端口 httpsUrl.port = HTTPS_PORT; // 301永久重定向 ctx.response.redirect(httpsUrl.toString()); ctx.response.status = 301; }); // 同时启动两个服务 async function startServers() { // 启动HTTPS服务 const httpsPromise = httpsApp.listen({ port: HTTPS_PORT, hostname: HOST, secure: true, certFile: CERT_FILE, keyFile: KEY_FILE }); console.log(`HTTPS服务监听端口 ${HTTPS_PORT} ...`); // 启动HTTP服务 const httpPromise = httpApp.listen({ port: HTTP_PORT, hostname: HOST }); console.log(`HTTP服务监听端口 ${HTTP_PORT} ...`); // 等待两个服务启动完成 await Promise.all([httpsPromise, httpPromise]); } // 示例respondWith实现(已有则可忽略) async function respondWith(ctx: Context, filePath: string) { const file = await Deno.readFile(filePath); ctx.response.body = file; ctx.response.headers.set('Content-Type', 'text/html'); } // 启动服务 startServers();
调整IPTABLES规则
将原有80端口转发指向HTTP服务端口,443端口保持指向HTTPS服务端口:
# 清除原有转发规则(如有需要) iptables -t nat -D PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 7700 iptables -t nat -D PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 7700 # 添加新转发规则 iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 7701 iptables -t nat -A PREROUTING -p tcp --dport 443 -j REDIRECT --to-port 7700
关键说明
- 两个服务实例相互独立,HTTP服务仅负责重定向,逻辑简单且不影响HTTPS服务稳定性
- 使用
Promise.all同时启动两个服务,避免阻塞 - 若域名已配置为默认443端口对外服务,重定向时可省略
httpsUrl.port设置,让浏览器自动使用443端口
内容的提问来源于stack exchange,提问作者Woodsy
相关产品推荐
相关产品推荐

