前后端分离模式下网页授权域名校验文件的上传方法。
# 背景
部分前后端分离项目需要用到公众号的网页授权来获取用户信息,但是添加网页授权域名需要从公众号管理后台下载文件再上传到前端项目的服务器上,所以显得比较繁琐。
# 解决办法
这里需要将前端上传的文件传给后端再由后端服务器去把文件回传至前端打包部署服务器的目录,而且文件只是一个简单的文本文件,所以可以使用scp或者命令创建txt的方式实现。
这里scp需要手输密码,免输需要提前在服务器设置密钥对,所以为了便捷选取shell命令创建文件的方式。
具体实现:
- 前端将文件上传至服务器后端
- 后端读取文件内容及文件名
- 后端ssh连接至目标服务器的指定目录(前端打包目录)
- 执行shell命令创建对应验证文件内容的文件
浏览器打开域名+验证文件名即可访问。
# 参考代码
前端为vue,后端为nodejs示例。
页面代码
<div id="app">
<el-upload class="upload-demo" :limit="1" drag accept=".txt" action="/uptxt"
:on-success="handleFileSuccess">
<i class="el-icon-upload"></i>
<div class="el-upload__text">将文件拖到此处,或<em>点击上传</em></div>
<div class="el-upload__tip" slot="tip">只能上传txt文件</div>
</el-upload>
</div>
<script>
const app = {
methods: {
handleFileSuccess(res, file, fileList) {
console.log(res)
this.fileName = res.data.fname
},
},
};
Vue.createApp(app).use(ElementPlus).mount('#app');
</script>
后端请求处理
app.use(bodyParser({
enableTypes: ['json', 'form', 'text']
}))
app.use(
koaBody({
multipart: true,
formidable: {
multipart: true,
maxFileSize: 50 * 1024 * 1024 // 设置上传文件大小最大限制
}
})
)
router.post('/uptxt', async (ctx) => {
if (!ctx.request.files) {
ctx.data = '未选择文件'
return
}
let file = ctx.request.files.file // 获取上传文件
let txt = fs.readFileSync(file.path, 'utf-8')
let res = await helper.upTxt(file.name, txt);
ctx.body = {
code: 0,
data: { fname: file.name, res: res },
msg: '',
};
});
后端上传代码
const { NodeSSH } = require('node-ssh');
let ssh = new NodeSSH();
const helper = {
// 初始化ssh连接
init(env, project) {
if (!ssh) {
ssh = new NodeSSH();
}
return new Promise((resolve, reject) => {
try {
ssh
.connect({
host: 'xxx',
username: 'xxx',
password: 'xxx',
port: xx,
})
.then(() => {
console.log('SSH login success');
resolve();
})
.catch((err) => {
console.log('SSH conneting fail:', err);
});
} catch (e) {
reject(e);
}
});
},
// 接收文件名及内容创建文件
upTxt(fName, content) {
return new Promise((resolve, reject) => {
try {
ssh
.execCommand(`echo '${content}' > ${fName} && cat ${fName}`, {
cwd: '/xxx/xxx/xxx',
})
.then((result) => {
if (!result.stderr) {
resolve(result.stdout);
} else {
console.log('Something wrong:', result);
resolve(result.stderr);
}
});
} catch (e) {
reject(e);
}
});
},
};
# 总结
本文只是提供一种思路及介绍简易的demo,不代表可以直接用于生产环境。如果您有更好的建议欢迎交流。