🚀 内网项目踩坑实录:从 HTTP 到 HTTPS 的血泪史
📋 TL;DR(Too Long; Didn’t Read)-概述
- 问题: 微信公众号爬虫在内网部署时无法登录
- 原因: HTTP 环境下无法设置 Secure Cookie + Deno KV 生产环境依赖
- 解决: 部署自签名 HTTPS + 删除用户存储功能
- 结果: 功能完美运行 ✨
🎯 项目背景
需求简述
开发一个微信公众号文章爬虫工具,供公司内部使用。由于数据安全要求,必须部署在内网环境。
技术栈
Framework: Nuxt.js 3
Runtime: Node.js
Proxy: Nginx
Panel: 宝塔面板
Environment: Ubuntu 22.04 + 内网 172.19.23.27
预期 vs 现实
| 环境 | 预期 | 现实 |
|---|---|---|
| 公网测试 | ✅ 完美运行 | ✅ 确实完美 |
| 内网部署 | 🤔 应该没问题吧 | 💥 完全不能用 |
🔥 问题一:Cookie 安全策略地狱
💀 症状描述
部署到内网后,用户扫码登录时:
- 二维码可以显示 ✅
- 扫码成功 ✅
- 点击登录… 毫无反应 ❌
宝塔配置如下:

通过反向代理打到本地3000端口,实现内网访问
🔍 错误现场
打开 F12,没有任何报错,甚至无法定位问题,此时的我非常焦虑,无论是多级反向代理还是跨域配置我都尝试了,并且长达两个小时都无法解决,此时我在本机ubantu的firefox才看到具体的报错信息,如图所示:

这真的让我非常难顶!!!排查了这么久,firefox直接就帮我定位了问题。(:
🚫 Cookie "slave_user" has been rejected because a non-HTTPS cookie can't be set as "secure"
🚫 Cookie "master_sid" has been rejected because a non-HTTPS cookie can't be set as "secure"
🚫 Cookie "bizuin" has been rejected because a non-HTTPS cookie can't be set as "secure"
🚫 Cookie "data_ticket" has been rejected because a non-HTTPS cookie can't be set as "secure"
... (重复 N 遍)
💡 第一反应: 这什么鬼?为什么公网好好的,内网就不行?
🕵️ 深入调查
问题根源
微信公众平台返回的 Cookie 长这样:
Set-Cookie: slave_user=xxx; Path=/; Secure; SameSite=None; HttpOnly
Set-Cookie: master_sid=yyy; Path=/; Secure; SameSite=None; HttpOnly
关键在于 Secure 标志!
浏览器安全策略
if (cookie.hasSecureFlag && location.protocol !== 'https:') {
console.error('🚫 Cookie rejected: non-HTTPS environment')
return false
}
环境对比
| 环境 | 协议 | Cookie 设置 | 结果 |
|---|---|---|---|
| 公网 | https:// | ✅ 允许 Secure Cookie | 🎉 登录成功 |
| 内网 | http:// | ❌ 拒绝 Secure Cookie | 💥 登录失败 |
💡 解决思路
既然浏览器严格要求 HTTPS 才能设置 Secure Cookie,而微信登录又必须依赖这些 Cookie,那只有一个办法:
给内网环境配置 HTTPS!
🛠️ HTTPS 部署实战
Step 1: 生成自签名证书
# 一键生成支持多地址的证书
openssl req -x509 -newkey rsa:2048 \
-keyout server.key -out server.pem \
-days 365 -nodes \
-config <(
echo '[dn]'
echo CN=172.19.23.27
echo '[req]'
echo distinguished_name = dn
echo '[EXT]'
echo subjectAltName=@alt_names
echo '[alt_names]'
echo DNS.1=localhost
echo DNS.2=wechatccc.com
echo IP.1=172.19.23.27
) -extensions EXT
Step 2: 宝塔面板配置
- 网站设置 → SSL 选项
- 选择”其他证书”
- 将
server.pem内容粘贴到”证书(PEM格式)” - 将
server.key内容粘贴到”密钥(KEY)” - 保存并启用 HTTPS
Step 3: Nginx 配置
宝塔会自动生成配置,核心部分:
server {
listen 80;
listen 443 ssl http2;
server_name 172.19.23.27 wechatccc.com;
# 🔒 SSL 证书配置
ssl_certificate /www/server/panel/vhost/cert/domain/fullchain.pem;
ssl_certificate_key /www/server/panel/vhost/cert/domain/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
# 🔄 反向代理到 Nuxt 应用
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Proto $scheme;
# ... 其他标准代理配置
}
}
🎯 问题一解决
访问 https://172.19.23.27:
- ⚠️ 浏览器显示”不安全”警告(自签名证书)
- ✅ 点击”高级” → “继续访问”
- ✅ Cookie 设置成功,登录流程恢复正常
🔥 问题二:Deno KV 生产环境炸弹
💣 新的爆炸
刚解决 Cookie 问题,结果点击登录后又炸了:
{
"statusCode": 500,
"message": "Could not find a Deno KV for production, make sure to deploy on Deno Deploy."
}
🤔 心理活动: 什么?我明明用的是 Node.js,怎么扯到 Deno 了?
🔍 代码考古
发现用户存储模块有这样的逻辑:
export async function createUser(user: UserEntry): Promise<boolean> {
if (process.dev) { // 🟢 开发环境:直接跳过
return Promise.resolve(true)
}
// 🔴 生产环境:尝试连接 Deno KV
const kv = await useKv() // 💥 爆炸点
// ... 复杂的用户存储逻辑
}
📊 环境差异分析
| 环境类型 | NODE_ENV | process.dev | 执行路径 | 结果 |
|---|---|---|---|---|
| 开发环境 | development | true | 跳过 KV | ✅ 正常 |
| 生产环境 | production | false | 连接 KV | 💥 报错 |
原来如此! 开发环境下代码会跳过用户存储,所以没问题。但生产环境会尝试连接 Deno KV 数据库,而我的部署环境是 Node.js,当然找不到!
🤔 功能必要性评估
仔细思考用户存储功能:
- 作用: 用户信息持久化、多账号管理、登录状态保持
- 对爬虫的必要性: 🤷♂️ 不是核心功能
- 复杂度: 🔴 增加部署复杂性
决策: 直接删除用户存储功能,专注核心爬虫能力!
💡 简单粗暴的解决方案
直接让所有用户存储函数返回成功/空值:
export async function createUser(user: UserEntry): Promise<boolean> {
// 🚀 直接返回成功,不存储任何用户信息
console.log(`📝 跳过用户创建: ${user.nickname}`)
return Promise.resolve(true)
}
export async function getUser(originalID: string): Promise<UserEntry | null> {
// 🚀 直接返回 null,表示"新用户"
return null
}
export async function getUserByUUID(uuid: string): Promise<UserEntry | null> {
return null
}
export async function getUserByFakeID(fakeid: string): Promise<UserEntry | null> {
return null
}
🎉 最终效果
✅ 功能验证
# 🔗 HTTPS 访问
curl -I https://172.19.23.27
# HTTP/2 200 ✅
# 🍪 Cookie 设置
# F12 → Application → Cookies → 看到完整的微信认证 Cookie ✅
# 🔐 登录流程
# 扫码 → 点击登录 → 跳转成功 ✅
# 🕷️ 爬虫功能
# 数据爬取完全正常 ✅
📈 性能表现
响应时间: 200-500ms
稳定性: 24h 无异常
资源占用:
CPU: < 5%
Memory: < 200MB
用户体验: 🌟🌟🌟🌟🌟
🎓 经验总结
💎 核心洞察
1. 安全策略进化论
现代浏览器对 Cookie 安全要求越来越严格:
Secure标志强制要求 HTTPSSameSite=None必须配合 HTTPS 使用- 即使内网环境也无法例外
2. 环境一致性的重要性
- 开发环境: HTTP + 跳过复杂逻辑
+ 生产环境: HTTPS + 完整功能实现
= 隐藏问题,部署时爆炸 💥
3. Keep It Simple, Stupid!
当遇到复杂的依赖问题时,问问自己:
- 这个功能真的必要吗?
- 能不能用更简单的方式解决?
- 核心业务需求是什么?
🛡️ 避坑指南
Cookie 问题排查
- ✅ 优先检查浏览器控制台 Cookie 错误
- ✅ 确认协议匹配(HTTP vs HTTPS)
- ✅ 理解 Secure/SameSite 属性含义
数据库依赖管理
- ✅ 区分开发和生产环境的差异
- ✅ 评估功能的实际必要性
- ✅ 优先解决核心问题,再考虑完善功能
内网部署特殊性
- ✅ 不要以为内网就可以降低安全标准
- ✅ 自签名证书是内网 HTTPS 的好选择
- ✅ 简化架构,减少外部依赖
🚀 总结
这次踩坑经历的核心收获:
🔧 技术层面
- HTTPS 不是可选项:即使内网环境,现代 Web 应用也需要 HTTPS
- 自签名证书很实用:快速、简单、满足功能需求
- 功能删减有时比优化更有效:不必要的复杂性就是技术债务
🎯 工程思维
- 问题导向:专注解决实际问题,而不是实现所有功能
- 渐进式开发:先让核心功能工作,再考虑完善
- 简化优于复杂:能删就删,能简化就简化
💡 部署经验
- 环境一致性很重要:开发和生产环境的差异会隐藏问题
- 错误信息是最好的老师:仔细阅读错误信息,往往直接指向解决方案
- 内网不等于简单:现代 Web 标准不会因为内网而降低要求
🎬 结语
从 HTTP 到 HTTPS,从复杂的用户管理到简化的核心功能,这次部署经历让我深刻理解了:
🌟 工程不是艺术,而是在约束条件下找到最优解的过程。
有时候,删除代码比写代码更有价值。有时候,简单粗暴的方案比精巧复杂的设计更实用。
技术服务于业务,而不是相反。