起因

Coding  的旧版网站列表突然消失,以为要强制迁移新版

于是临时解析到了 Vercel,但是晚上它又好了

发现问题

但部署刷新几遍发现没有变化,当时德目录结构没有 live 文件夹里面放 index.html,会想到主页的.html后缀问题,我去前往主页分页查看,果然不加.html直接公益 404,那么就得为两种解析方式都准备好源文件

解决问题

主页怎么办

这是废话

const gulp = require("gulp");
const minifycss = require("gulp-clean-css");
const uglify = require("gulp-uglify");
const htmlmin = require("gulp-htmlmin");
const cssnano = require("gulp-cssnano");
const htmlclean = require("gulp-htmlclean");
const del = require("del");
const babel = require("gulp-babel");
const autoprefixer = require("gulp-autoprefixer");
const connect = require("gulp-connect");
const pug = require("gulp-pug");
const sass = require("gulp-sass");
const rename = require("gulp-rename");
sass.compiler = require("node-sass");

const config = require("./config.json");

gulp.task("clean", function () {
return del(["./dist/css/", "./dist/js/"]);
});

gulp.task("css", function () {
return gulp
.src("./src/css/*.scss")
.pipe(sass().on("error", sass.logError))
.pipe(minifycss({ compatibility: "ie8" }))
.pipe(autoprefixer({ overrideBrowserslist: ["last 2 version"] }))
.pipe(cssnano({ reduceIdents: false }))
.pipe(gulp.dest("./dist/css"));
});

gulp.task("html", function () {
return gulp
.src("./dist/*.html")
.pipe(htmlclean())
.pipe(htmlmin())
.pipe(gulp.dest("./dist"));
});

gulp.task("js", function () {
return gulp
.src("./src/js/*.js")
.pipe(babel({ presets: ["@babel/preset-env"] }))
.pipe(uglify())
.pipe(gulp.dest("./dist/js"));
});

gulp.task("pug", function () {
return gulp
.src("./src/*.pug")
.pipe(pug({ data: config }))
.pipe(gulp.dest("./dist"));
});
gulp.task("redirect", function (done) {
config.redirect.forEach((item) => {
// item 为redirect的列表
let data = {
redirect: item,
count: config.count,
template: item.template || "redirect",
};
gulp
.src(`./src/redirect/${data.template}.pug`)
.pipe(pug({ data: data }))
.pipe(rename("index.html"))
.pipe(gulp.dest(`./dist/${item.path}`));
});
done();
});
gulp.task("assets", function () {
return gulp.src(["./src/assets/**/*"]).pipe(gulp.dest("./dist/assets"));
});
gulp.task("staticHtml", function () {
return gulp.src(["./src/*.html"]).pipe(gulp.dest("./dist"));
});
gulp.task("test", gulp.series("redirect"));
gulp.task("LICENSE", function () {
return gulp.src(["./src/LICENSE"]).pipe(gulp.dest("./dist"));
});

gulp.task("txt", function () {
return gulp.src(["./src/*.txt"]).pipe(gulp.dest("./dist"));
});

gulp.task("md", function () {
return gulp.src(["./src/*.md"]).pipe(gulp.dest("./dist"));
});

gulp.task("sw", function () {
return gulp.src(["./src/*.js"]).pipe(gulp.dest("./dist"));
});

gulp.task(
"build",
gulp.series(
"clean",
"assets",
"staticHtml",
"pug",
"redirect",
"css",
"js",
"html",
"LICENSE",
"txt",
"md",
"sw"
)
);
gulp.task("default", gulp.series("build"));

gulp.task("watch", function () {
gulp.watch("./src/components/*.pug", gulp.parallel("pug"));
gulp.watch("./src/pages/*.pug", gulp.parallel("pug"));
gulp.watch("./src/*.pug", gulp.parallel("pug"));
gulp.watch("./src/css/**/*.scss", gulp.parallel(["css"]));
gulp.watch("./src/js/*.js", gulp.parallel(["js"]));
connect.server({
root: "dist",
livereload: true,
port: 4000,
});
});

以上仅作为存档备份,万一哪天改没了,不想去找历史记录

最笨的方法解决

为了保险起见,我还是要确保双目录,境内外都能正常跳转

//在生成静态文件并且压缩完毕后,新建文件夹,复制过去重命名为index.html即可保证coding,vercel都能不使用.html访问了,index.html和404.html因为两边都能正常跳转,我也不会通配,所以老老实实一条一条写(乐特说只有废物看文档,我就是废物,我还不想看)
gulp.task("about", function () {
return gulp
.src("./dist/about.html")
.pipe(rename("index.html"))
.pipe(gulp.dest("./dist/about"));
});

gulp.task("link", function () {
return gulp
.src("./dist/link.html")
.pipe(rename("index.html"))
.pipe(gulp.dest("./dist/link"));
});

gulp.task("speak", function () {
return gulp
.src("./dist/speak.html")
.pipe(rename("index.html"))
.pipe(gulp.dest("./dist/speak"));
});

gulp.task("timeline", function () {
return gulp
.src("./dist/timeline.html")
.pipe(rename("index.html"))
.pipe(gulp.dest("./dist/timeline"));
});

//同时按照顺序添加任务
gulp.task("build", gulp.series("html", "about", "link", "speak", "timeline"));

这样生成的文件目录和预期相同


但其实没必要这样麻烦,费力不讨好,改一改 gulpfile.js 这个文件生成文件的目录结构即可,或者往下看

结果

现在主页不管是Vercel还是Coding都能正常跳转脱掉.html了,并且可实现境外境内分流,限制境外用户访问某些页面(伪操作

比如现在访问主站点直播界面,若是境外用户会显示(Vercel)

但境内用户则正常(Coding)

分析

在路由表默认逻辑上,Vervel,Gitlab,一致,Github,Gitee``Coding,Netlify一致,所以上面的说法是不严谨的,用户可以在链接后加上.html则可正常访问相应内容,但至少所有镜像站点都可以正常跳转了,然后配合 DNS 分流解析即可实现上面的效果

简单方式

查看 Vercel 官方文档 发现如下内容

Vercel uses Routes to define the behavior of how a request is handled by the routing layer. For example, you might use a Route to proxy a URL to another, redirect a client, or apply a header with the response to a request.

By default, routing is defined by the filesystem of your deployment. For example, if a user makes a request to /123.png, and your vercel.json file does not contain any routes with a valid src matching that path, it will fallback to the filesystem and serve /123.png if it exists.

NOTE: For Serverless Function routes, you can configure an /api directory to provide filesystem routing and handle dynamic routing with path segments, without the need for configuration.

A Route can be defined within a project’s vercel.json configuration file as an object within an array assigned to the routes property, like the following which creates a simple proxy from one path to another:

{
"routes": [{ "src": "/about", "dest": "/about.html" }]
}

An example vercel.json file with a routes property that proxies one path to another upon request.

Vercel Routes have multiple properties for each route object that help define the behavior of a response to each request to a particular path.

src

Type: String supporting PCRE Regex and Route Parameters like /product/(?<id>[^/]+).

For each route, src is required to set the path which the behavior will affect.

The following example shows a vercel.json configuration that takes a src path and proxies it to a destinationdestpath.

{
"routes": [{ "src": "/about", "dest": "/about.html" }]
}

An example vercel.json file with a routes property that proxies one path to another upon request.

dest

Type: String

dest is used to proxy the src path to another path, such as another URL or Vercel hosted Serverless Function.

The example for thesrcproperty shows how both methods work together to create a proxy.

{
"routes": [
{ "src": "/about", "dest": "https://about.me" },
{ "src": "/action", "dest": "my-serverless-function-action/index" }
]
}

An example vercel.json file with routes properties that proxy paths to another upon request.

NOTE: You can point the dest path to any URL, Vercel hosted Serverless Function, or even non Vercel hosted URLs as shown in the code above. If you don’t perform any proxying, you can safely remove dest.

{
"routes": [{ "src": "/about" }]
}

This will route to /about without proxying, but routes like this are usually redundant with handle filesystem.

这代表着我们可以按照上面的方式自定义路由表:即在根目录创建vercel.json来完成自定义,并完美去掉.html,解决这个问题,并且个人也是推荐这种更为简单的方法;而查看文档,我才发现 Vercel 真的是一个强大的静态托管平台,笔芯!

所以 Vercel 方面,以我主页为例,就可以通过以下代码来解决啦

{
"routes": [
{ "src": "/about", "dest": "/about.html" },
{ "src": "/link", "dest": "/link.html" },
{ "src": "/speak", "dest": "/speak.html" },
{ "src": "/timeline", "dest": "/timeline.html" }
]
}