You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 03:42:53