Windows下数据资源公开访问之环境搭建方法(2023.1.2)
- 1、需求分析
- 2、常用的解决方案
- 2.0 前提环境(Java + Node)
- 2.1 方案一:利用现有服务器容器(以Tomcat为例)
- 2.1.1 下载Tomcat并解压
- 2.1.2 配置系统环境变量
- 2.1.3 修改Tomcat服务器配置文件并启动
- 2.2 方案二:自己搭建服务器容器
- 2.2.1 Vue
- 2.2.2.1 Node全局安装Vue和Webpack依赖
- 2.2.2.2 Vue项目初始化构建
- 2.2.2.3 复制文件到static目录重启访问
- 2.2.2 Express
- 2.2.2.1 所需文件1(package.json)
- 2.2.2.2 所需文件2(server.js)
- 2.2.2.3 启动Web应用访问数据资源文件
- 3、三种方法简单对比
- 4、总结
1、需求分析
Web
开发者和客户在很多情况下都会从网络上下载资源文件,如安装包文件(.iso、.exe、.msi)、依赖库文件(.dll、.lib)、压缩文件(.zip、.rar、.tar.gz)、图片文件(.png、.jpg、.gif、.ico、.tif、.mat)、表格文件(.xls、.xlsl、.csv)、文本文件(.txt、.dat、.json)、代码文件(.c、.cpp、.h、.hpp、.java、.py、.m、.cs、.js、.scala、.bat、.cmd)
,而网络上的各类文件(本质为数据
)均可称之为资源Resource,之所以能够被网友下载,是因为这些文件寄存在网络服务器上,它们被放置在服务器特定的文件夹下,通过统一资源定位符URL或统一资源索引URI来标识,以便用户进行下载,当然对于image图片或json文本或pdf文档等数据
可支持浏览器在线查看。注:这里关注的仅仅是数据资源,暂不讨论模型计算资源和服务资源。
有一天,开发者或者企业想要给客户分享资源,当然这里仅讨论公开的资源,这些资源需要寄宿到一个Web服务器上,这时开发者应该如何去实现呢?
2、常用的解决方案
当然,想要解决数据资源公开访问的问题,可从以下两个方面入手:(1)开发者和工程师自己写一个服务器容器,将本地文件挂靠在其中;(2)依托现有的网络服务器,通过本地部署,将资源文件及数据安置其中。 毋庸置疑的是,这两种方式在最终呈现给用户时,都需要使用接受工信部备案的公网IP
来让广大客户公开访问,有经济能力的个人或企业会购买域名,这样将域名与公网IP进行绑定,就可直接利用域名地址拼接服务器资源URL为用户提供访问和下载服务。
2.0 前提环境(Java + Node)
本文所提到的解决方案涉及Java
环境和Nodejs
运行时环境,对于Java
环境,可安装Java 8
或Java 11
;对于Nodejs
直接安装即可,版本不要太低。Java 11+Nodejs为本文的测试环境。
|
|
2.1 方案一:利用现有服务器容器(以Tomcat为例)
Tomcat作为强大的开源服务容器,一直以来深受广大开发者的喜爱。随着版本的不断更新,Tomcat
的版本也需要与Java
版本相适配。
2.1.1 下载Tomcat并解压
到Tomcat官网下载免安装版压缩包文件,下载完成后解压,这里解压到了E:\jing_zhong\apache-tomcat-11.0.0-M1
文件夹。
2.1.2 配置系统环境变量
点击计算机(我的电脑)>>>右键>>>属性>>>高级系统设置>>>环境变量,设置系统环境变量JAVA_HOME
、CATALINA_HOME
、CATA_LINA_BASE
为E:\jing_zhong\apache-tomcat-11.0.0-M1(注:Tomcat解压文件夹),在配置好上述变量后,可以利用键盘组合键Win+R打开cmd
命令行窗口,通过输入如下命令来检查系统变量是否设置生效:
|
|
|
|
这里我选择的tomcat v11.0.0
必须使用Java 11
,而不能使用Java 8
,Win+R打开命令行窗口,依次输入命令echo %JAVA_HOME%
、echo %CATALINA_HOME%
、echo %CATALINA_BASE%
来测试环境变量是否配置成功,如果成功则如下图所示:
2.1.3 修改Tomcat服务器配置文件并启动
在添加完系统环境变量后,还需要对Tomcat
服务器的相关配置进行修改,具体内容如下:
打开conf目录下的logging.properties文件,在 java.util.logging.ConsoleHandler.encoding = UTF-8后添加以下代码可设置Tomcat服务器在控制台显示中文乱码的问题;
java.util.logging.ConsoleHandler.encoding = GBK
打开conf目录下的server.xml文件,找到Connector标签下的port属性,将默认端口8080改为8084;
默认端口为8080
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
修改端口为8084
<Connector port="8084" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
打开conf目录下的server.xml文件,向内部添加虚拟路径映射,在文件最后添加如下代码:
<Context path="/jing_zhong" docBase="E:/jing_zhong/gulp-learn/Build/Documentation" reloadable="false" ></Context>
打开conf目录下的web.xml文件,将listings的值由false修改为true。
最后双击bin
目录下的startup.bat
来启动Tomcat
服务器,然后打开浏览器访问资源文件地址即可。
|
|
|
|
|
|
2.2 方案二:自己搭建服务器容器
这里所谓的自己搭建服务器并不意味着从底层开始写,那样工作量庞大且对技能要求较高,同时缺乏高效性和实时性,短期很难实现,因此还是借助Web应用作为服务器来放置数据资源以提供给用户进行访问
,下面主要以Vue和Express为例来进行介绍。
2.2.1 Vue
作为一个优秀的前端开发框架,Vue毫无疑问受到广大开发者的一致好评,并且有着遍地开花的广泛应用。
2.2.2.1 Node全局安装Vue和Webpack依赖
利用命令npm install --global vue
和 npm install --global webpack
来在全局安装Vue和Webpack,然后Win>+R打开命令行窗口,输入以下命令来验证依赖包是否安装成功:
node -v
vue -V
webpack -v
2.2.2.2 Vue项目初始化构建
在Vue
和Webpack
安装成功后,同样在命令行窗口进入自己所选的文件夹,输入如下命令(含初始化项目+进入项目文件夹+启动项目
)快速搭建一个以Webpack
为构建的Vue
项目。
vue init webpack test-Vue
cd test-Vue
npm run dev
2.2.2.3 复制文件到static目录重启访问
用记事本打开config
文件夹下的index.js
,将默认端口号8080修改为8085,如下图所示:
|
|
之后将自己想要分享的数据资源文件放置在test-Vue
项目的static
文件夹下,重新启动项目(npm run dev)即可访问数据文件并下载。
|
|
|
|
|
|
|
2.2.2 Express
Express 可基于Node.js快速构建Web应用,十分强大的同时又不失灵活性,如果想要深入了解可参考Node.js Express 框架学习。
2.2.2.1 所需文件1(package.json)
在E:\jing_zhong\MyServer文件夹下新建一个记事本文件,将文件重命名为package.json
,将以下内容复制到package.json
文件内:
{
"name": "MyServer",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"compression": "^1.7.4",
"express": "^4.18.2",
"expression": "0.0.1",
"fs": "0.0.1-security",
"mime": "^3.0.0",
"request": "^2.88.2",
"url": "^0.11.0",
"yargs": "^17.6.2"
}
}
2.2.2.2 所需文件2(server.js)
在E:\jing_zhong\MyServer文件夹下新建一个记事本文件,将文件重命名为server.js
,将以下内容复制到server.js
文件内:
"use strict";
(function () {
const express = require("express");
const compression = require("compression");
const fs = require("fs");
const url = require("url");
const request = require("request");
const gzipHeader = Buffer.from("1F8B08", "hex");
const yargs = require("yargs").options({
port: {
default: 8084,
description: "Port to listen on.",
},
public: {
type: "boolean",
description: "Run a public server that listens on all interfaces.",
},
"upstream-proxy": {
description:
'A standard proxy server that will be used to retrieve data. Specify a URL including port, e.g. "http://proxy:8004".',
},
"bypass-upstream-proxy-hosts": {
description:
'A comma separated list of hosts that will bypass the specified upstream_proxy, e.g. "lanhost1,lanhost2"',
},
help: {
alias: "h",
type: "boolean",
description: "Show this help.",
},
});
const argv = yargs.argv;
if (argv.help) {
return yargs.showHelp();
}
const mime = express.static.mime;
mime.define(
{
"application/json": ["czml", "json", "geojson", "topojson"],
"application/wasm": ["wasm"],
"image/ktx2": ["ktx2"],
"model/gltf+json": ["gltf"],
"model/gltf-binary": ["bgltf", "glb"],
"application/octet-stream": [
"b3dm",
"pnts",
"i3dm",
"cmpt",
"geom",
"vctr",
],
"text/plain": ["glsl"],
},
true
);
const app = express();
app.use(compression());
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header(
"Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept"
);
next();
});
function checkGzipAndNext(req, res, next) {
const reqUrl = url.parse(req.url, true);
const filePath = reqUrl.pathname.substring(1);
const readStream = fs.createReadStream(filePath, { start: 0, end: 2 });
readStream.on("error", function (err) {
next();
});
readStream.on("data", function (chunk) {
if (chunk.equals(gzipHeader)) {
res.header("Content-Encoding", "gzip");
}
next();
});
}
app.use(express.static(__dirname));
function getRemoteUrlFromParam(req) {
let remoteUrl = req.params[0];
if (remoteUrl) {
// add http:// to the URL if no protocol is present
if (!/^https?:\/\//.test(remoteUrl)) {
remoteUrl = "http://" + remoteUrl;
}
remoteUrl = url.parse(remoteUrl);
// copy query string
remoteUrl.search = url.parse(req.url).search;
}
return remoteUrl;
}
const dontProxyHeaderRegex = /^(?:Host|Proxy-Connection|Connection|Keep-Alive|Transfer-Encoding|TE|Trailer|Proxy-Authorization|Proxy-Authenticate|Upgrade)$/i;
function filterHeaders(req, headers) {
const result = {};
// filter out headers that are listed in the regex above
Object.keys(headers).forEach(function (name) {
if (!dontProxyHeaderRegex.test(name)) {
result[name] = headers[name];
}
});
return result;
}
const upstreamProxy = argv["upstream-proxy"];
const bypassUpstreamProxyHosts = {};
if (argv["bypass-upstream-proxy-hosts"]) {
argv["bypass-upstream-proxy-hosts"].split(",").forEach(function (host) {
bypassUpstreamProxyHosts[host.toLowerCase()] = true;
});
}
app.get("/proxy/*", function (req, res, next) {
let remoteUrl = getRemoteUrlFromParam(req);
if (!remoteUrl) {
remoteUrl = Object.keys(req.query)[0];
if (remoteUrl) {
remoteUrl = url.parse(remoteUrl);
}
}
if (!remoteUrl) {
return res.status(400).send("No url specified.");
}
if (!remoteUrl.protocol) {
remoteUrl.protocol = "http:";
}
let proxy;
if (upstreamProxy && !(remoteUrl.host in bypassUpstreamProxyHosts)) {
proxy = upstreamProxy;
}
request.get(
{
url: url.format(remoteUrl),
headers: filterHeaders(req, req.headers),
encoding: null,
proxy: proxy,
},
function (error, response, body) {
let code = 500;
if (response) {
code = response.statusCode;
res.header(filterHeaders(req, response.headers));
}
res.status(code).send(body);
}
);
});
const server = app.listen(
argv.port,
argv.public ? undefined : "localhost",
function () {
if (argv.public) {
console.log(
"Your server running publicly. Connect to http://localhost:%d/",
server.address().port
);
} else {
console.log(
"Your server running locally. Connect to http://localhost:%d/",
server.address().port
);
}
}
);
server.on("error", function (e) {
if (e.code === "EADDRINUSE") {
console.log(
"Error: Port %d is already in use, select a different port.",
argv.port
);
console.log("Example: node server.cjs --port %d", argv.port + 1);
} else if (e.code === "EACCES") {
console.log(
"Error: This process does not have permission to listen on port %d.",
argv.port
);
if (argv.port < 1024) {
console.log("Try a port number higher than 1024.");
}
}
console.log(e);
process.exit(1);
});
server.on("close", function () {
console.log("Your server stopped.");
});
let isFirstSig = true;
process.on("SIGINT", function () {
if (isFirstSig) {
console.log("Your server shutting down.");
server.close(function () {
process.exit(0);
});
isFirstSig = false;
} else {
console.log("Your server force kill.");
process.exit(1);
}
});
})();
2.2.2.3 启动Web应用访问数据资源文件
将数据资源文件或文件夹拷贝到MyServer
文件夹下,然后Win>+R打开命令行窗口,依次输入如下命令来启动Web应用,即可成功访问数据资源。
npm install
node server.js --port 8086
|
|
|
|
|
|
3、三种方法简单对比
通过对比Tomcat、Vue、Express
这三种访问公开数据资源的搭建方法,得出如下表所示的结论。
维度\方法 | Tomcat | Vue | Express |
---|---|---|---|
搭建方法 | Tomcat无疑更加灵活,能够进行本地文件夹的虚拟地址映射,在映射完成后可以在浏览器中公开访问文件夹及其中的文件 | 能访问文件,不能访问文件夹,需要提供准确的数据资源地址,尽管可以配置代理Proxy来进行虚拟地址映射,但过程较为繁琐 | 能访问文件,不能访问文件夹,需要提供准确的数据资源地址,尽管可以配置代理Proxy来进行虚拟地址映射,但过程较为繁琐 |
访问自由度 | Tomcat方式则需要配置环境变量,修改相关配置文件,无需手动复制或移动文件夹和数据资源 | Vue方式需要安装一些可选的依赖包,初始化速度不如Express快,但时间也较短,需要移动数据资源到项目目录下,改变需要重启; | Express方式十分轻便高效,可以在较短时间内搭建完成,需要移动数据资源到项目目录下,但改变无需重启 |
并发稳定性 | 当用户并发数增多,Tomcat相对于Vue和Express来说更加稳定,能够设置并发数量,具有不错的扛并发访问能力,可配置在内网和公网供几百个用户访问 | Web应用一般为开发环境,尽管可以部署,但很难支持强大的用户并发访问数量,建议在局域网或内网供小规模的开发团队或少的用户来使用 | Web应用一般为开发环境,尽管可以部署,但很难支持强大的用户并发访问数量,建议在局域网或内网供小规模的开发团队或少的用户来使用 |
4、总结
最后,浅谈一下我个人的实际体验,当然不一定对哦!!!🌈🌈🌈本人比较喜欢Tomcat方式,因为可配置多个Tomcat
,每个Tomcat下可进行多个数据资源的虚拟地址映射
,以供用户访问下载,比较稳定,适合大规模多用户高并发的访问场景
;当然Vue
和Express
这两种方式对于临时的文件资源共享也十分方便,适合API及文档共享、团队代码开发协作、小用户量的数据资源下载等场景。从实际应用来讲,各种框架和开源服务器软件很多,但需要自己亲自尝试来对比效果和性能,目前我觉得还是得先明确自己的实际需求,分析关注的维度指标,因时因地制宜,选择适合业务应用的环境搭建方法。