用 FontMod 给 Fusion 360 换上 MiSans 字体(无需安装到系统)

用 FontMod 给 Fusion 360 换上 MiSans 字体(无需安装到系统)

一个手把手教程,包含配置文件和常见坑

为什么要折腾?

Fusion 360 默认的字体在高分屏下不够美观,尤其是中文字体渲染发虚、锯齿感明显。而我比较喜欢小米的 MiSans 字体,干净现代。但是 Fusion 360 本身不支持直接换字体,只能借助外部工具。

在网上找到了 FontMod 这个开源项目,它可以通过 DLL 劫持的方式,修改 Win32 程序的字体。经过一番尝试,成功让 Fusion 360 用上了 MiSans,而且不需要把字体安装到系统,绿色无污染。

下面记录完整步骤。

FontMod 是什么?

简单说,它是一个 Hook 工具,可以拦截程序调用 GDI/GDI+ 创建字体的请求,然后替换成你指定的字体。支持通过配置文件灵活控制。

项目地址:
https://github.com/ysc3839/FontMod

准备工作

  1. 下载 FontMod
    Releases 页面 下载对应架构的 DLL:
    • 64 位系统选 FontMod64.dll
    • 32 位系统选 FontMod32.dll
  2. 下载 MiSans 字体
    小米官网或 GitHub 上可以找到 MiSans 字体包。解压后找到 MiSans-Regular.ttf(或其他字重,我用的 Regular)。
    注意:只需要 TTF/OTF 格式,不需要 WOFF/WOFF2。
  3. 找到 Fusion 360 的安装目录
    通常类似:
    C:\Program Files\Autodesk\Fusion 360\
    或者 C:\Users\你的用户名\AppData\Local\Autodesk\Fusion 360\(具体看安装位置)。

操作步骤

1. 放置 FontMod DLL

将下载的 FontMod64.dll 重命名为 version.dll,然后复制到 Fusion 360 的安装目录(即与 Fusion360.exe 相同的文件夹)。

为什么选 version.dll

  • 几乎所有 Windows 程序都会加载这个 DLL,兼容性最好。
  • 不会覆盖任何原有文件(程序目录下本来没有这个文件),所以完全可逆。

2. 创建 fonts 文件夹

在 Fusion 360 安装目录下,新建一个名为 fonts 的文件夹

MiSans-Regular.ttf 复制进去。
最终目录结构类似:

1
2
3
4
5
6
Fusion 360/
├── version.dll ← 重命名后的 FontMod
├── FontMod.yaml ← 稍后自动生成或手动创建
├── fonts/
│ └── MiSans-Regular.ttf
└── ...(其他原始文件)

3. 编写配置文件

首次运行 Fusion 360 时,FontMod 会在同目录自动生成一个 FontMod.yaml 配置文件。你可以直接编辑它,或者手动创建。

用记事本(或 VS Code)打开,写入以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
style: &style
# 重要:不要设置 size,否则 Fusion 360 可能闪退
# size: 0

fonts:
# 简体中文 fallback 字体
SimSun: &MiSansFont
replace: MiSans # 注意:这是字体内部的名称,不是文件名
<<: *style

# 常见英文 / UI 字体
Arial: *MiSansFont
Tahoma: *MiSansFont
Segoe UI: *MiSansFont
Microsoft Sans Serif: *MiSansFont

# 如果字体没生效,可以开启调试
debug: false

关键点说明:

  • replace: MiSans —— 这里的 MiSans 是字体文件内部的“字体族名”,而不是文件名 MiSans-Regular
    你可以右键 .ttf 文件 →“预览”,顶部显示的名称就是正确的值。
  • 千万不要设置 size 属性。在 Fusion 360 中修改字体大小极易导致启动闪退,保持注释状态即可。
  • 如果需要替换其他语言(繁体、日文、韩文),可以继续添加 PMingLiUMS UI Gothic 等条目,但没必要 —— 因为那些文字的 fallback 最终也会走到 SimSun,从而被替换成 MiSans。

4. 启动 Fusion 360

正常启动软件,如果一切顺利,界面字体应该已经变成 MiSans 了。
如果没有变化,可以:

  • 检查 version.dll 是否放对了位置(与主 exe 同目录)。
  • 检查 fonts 文件夹名称是否正确(必须是 fonts)。
  • 将配置文件中的 debug: false 改为 debug: true,重启软件,然后查看生成的 FontMod.log 文件,里面会记录被拦截的原始字体名,可以据此调整配置中的 key(比如把 SimSun 换成日志里出现的其他字体)。

常见问题

Q:替换 version.dll 会不会影响 Fusion 360 的正常功能?

不会。FontMod 只是一个“中间人”,它会拦截字体相关调用,然后把其他所有请求**转发给系统的真实 version.dll**。原始功能完全不受影响。

Q:如果 Fusion 360 更新了,需要重新操作吗?

通常不需要。更新可能会覆盖安装目录下的文件,但 version.dllfonts 文件夹不会被删除。如果不放心,可以备份一下配置文件。

Q:MiSans-Regular 字重太细/太粗怎么办?

你可以换用其他字重,比如 MiSans-Medium.ttfMiSans-Demibold.ttf
注意:字重文件内部的字体族名仍然是 MiSans,所以配置文件不需要改,只需要替换 fonts 文件夹里的字体文件即可。
FontMod 会根据程序请求的字重自动匹配最接近的可用文件(如果只有一个 Regular,可能会 fallback 到 Regular,但日常使用影响不大)。

Q:我用了其他字体(比如 OPPO Sans)怎么改?

只需修改配置文件中的 replace 值,换成对应字体的族名,然后把字体文件放入 fonts 文件夹即可。

总结

整个流程并不复杂:

  1. 下载 FontMod,重命名为 version.dll 放进程序目录。
  2. 创建 fonts 文件夹,放入字体文件。
  3. 编写 FontMod.yaml,替换掉 SimSunArial 等常见字体。
  4. 启动软件,享受新字体。

唯一要注意的是不要设置字体大小,避免 Fusion 360 闪退。
如果你也厌倦了默认的宋体,不妨试试这个方法。折腾半小时,舒适一整年 😄


参考资料:

1Panel管理后台使用Let'sEncrypt自动续签阿里云域名HTTPS证书

在1Panel后台菜单选择【网站/证书/Acme账户】

然后创建Acme账户

  • 邮箱(输入你自己的邮箱就行)

去阿里云创建RAM用户获取AccessKey和SecretKey

可以参照这个文档:https://help.aliyun.com/zh/ram/user-guide/create-an-accesskey-pair

注意!创建的用户一定要记得添加权限,不然等下申请证书会没权限

在1Panel后台菜单选择【网站/证书/DNS账户】

然后创建DNS账户

  • 名称(随意)
  • Access key(需要在阿里云去创建)
  • Secret key(需要在阿里云去创建)

在1Panel后台菜单选择【网站/证书/申请证书】

这下可以申请证书了

  • 主域名(这里填写你的主域名)
  • 其他域名(这里填写你的子域名)
  • Acme账户(选择你刚才创建的Acme账户)
  • DNS账户(选择你刚才创建的DNS账户)

点击确认 申请!

大概等待5分钟左右就可以申请成功了

这种方式支持自动续签,再也不用阿里云恶心的3个月免费证书了

简单实现一个useSignal

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
export const useSignal = (initialState) => {
const [state, setState] = useState(initialState)
const stateRef = useRef(initialState)

const getState = () => stateRef.current

const editState = (newState) => {
setState(newState)

if (typeof newState === 'function'){
stateRef.current = newState(stateRef.current)
} else {
stateRef.current = newState
}
}

return [state, editState, getState]
}

2024-05-16 一个Npm包"hanzi-utils",提供了一些汉字相关的处理函数.md

汉字处理工具库

简介

本库提供了一系列用于处理汉字(中文字符)的JavaScript函数。这些函数包括查询汉字的异体字、发音、部首、笔画、获取所有Unicode汉字、Unicode编码与汉字字符的转换以及计算汉字字符串的长度等。

安装

1
npm i @vearvip/hanzi-utils

使用

引入模块

首先,确保你已经将@vearvip/hanzi-utils引入到你的项目中。

查询汉字的异体字

1
2
3
4
5
6
7
import { queryVariant } from '@vearvip/hanzi-utils';

const character = '说';
const variants = queryVariant(character);

console.log(`"${character}" 的异体字有:`, variants);
// "说" 的异体字有: [ "說", "説" ]

查询汉字的部首、笔画

1
2
3
4
5
6
7
import { queryRadicalStrokeCount } from '@vearvip/hanzi-utils';

const hanzi = '额';
const result = queryRadicalStrokeCount(hanzi);
console.log(result); // 输出:[ "页", 15 ]

// 解释:汉字"额"的部首是"页",总笔画数为15。

查询汉字在多种方言和语言中的读音,当前支持以下方言/语言的读音查询:

  • 普通话(mandarin)
  • 粤语(cantonese)
  • 日语音读(japaneseOn)
  • 日语训读(japaneseKun)
  • 韩语(korean)
  • 越南语(vietnamese)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import { queryReading } from '@vearvip/hanzi-utils';

// 查询汉字“一”的粤语、日语、韩语、普通话及越南语读音
const readings = queryReading('一');
console.log(readings);
/*
输出:
{
kCantonese: "jat1",
kJapaneseKun: "HITOTSU HITOTABI HAJIME",
kJapaneseOn: "ICHI ITSU",
kKorean: "IL",
kMandarin: "yī",
kVietnamese: "nhất",
}
*/

获取所有Unicode的汉字(截止Unicode 版本:15.1,本函数可返回99142个汉字,实际只有99139个,因为部首扩展:2E9A 是空码位,兼容汉字:FA6E、FA6F 是空码位。)

1
2
3
4
5
6
7
import { getAllHanziCharacters } from '@vearvip/hanzi-utils';

const allHanzi = getAllHanziCharacters();
console.log(allHanzi.slice(0, 10));
// [ "一", "丁", "丂", "七", "丄", "丅", "丆", "万", "丈", "三"]
console.log(allHanzi.length);
// 99142

Unicode编码与汉字字符的转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { 
unicode2Hanzi,
hanzi2Unicode,
} from '@vearvip/hanzi-utils';

// Unicode编码转汉字字符
const hexCode = '4E2D'; // '中'的Unicode编码
const hanzi = unicode2Hanzi(hexCode);
console.log(hanzi); // 输出:中

// 汉字字符转Unicode编码
const anotherHanzi = '字';
const unicode = hanzi2Unicode(anotherHanzi);
console.log(unicode); // 输出:5B57

计算汉字字符串的长度

1
2
3
4
5
6
import { unicodeLengthIgnoreSequence } from '@vearvip/hanzi-utils';

const str = '豕型';
const strLength = unicodeLengthIgnoreSequence(str);
console.log(str.length); // 输出:4
console.log(strLength); // 输出:2

函数检查一个字符是否是汉字

1
2
3
4
5
import { isHanzi } from '@vearvip/hanzi-utils';

console.log(isHanzi('汉')); // true
console.log(isHanzi('A')); // false
console.log(isHanzi('𠀀')); // true

提取字符串中的汉字

1
2
3
import { extractHanzi } from '@vearvip/hanzi-utils';

console.log(extractHanzi('Hello, 世界! 𠀀✨ 你好,世界!')); // 输出: ["世", "界", "𠀀", "你", "好", "世", "界"]

注意事项

  • 本库中的函数假设你正在使用支持ES6及以上语法的JavaScript环境。
  • unicodeLengthIgnoreSequence使用了Intl.Segmenter,请确保你的JavaScript环境支持该API(通常在较新的浏览器和Node.js版本中可用)。
  • 本库的代码未经优化,可能不适用于大型项目或需要高性能的场景。如有需要,请进行适当的性能优化。

贡献

如果你发现任何错误或想要提出改进建议,请随时通过GitHub或其他方式联系我。欢迎任何形式的贡献!

2023-11-10 JS复制表格到Excel.md

简单示例,这里用的是Fusion的Table

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
import { Table, Button } from "@alifd/next";

function App() {

const dataSource = [
{
item: '棉鞋1',
img: 'https://img.alicdn.com/imgextra/i3/O1CN01oa2oWk1THYOTjD8um_!!6000000002357-2-tps-110-110.png',
sku: '34码',
amount: 999,
induction: {
a: 10,
b: 12
}
},
{
item: '棉鞋1',
img: 'https://img.alicdn.com/imgextra/i2/O1CN010URR3q1qa5aKdpsOh_!!6000000005511-2-tps-110-110.png',
sku: '35码',
amount: 88,
induction: {
a: 23,
b: 77
}
},
{
item: '拖鞋1',
img: 'https://img.alicdn.com/imgextra/i4/O1CN01xUEUfU1TCyQuxXEps_!!6000000002347-2-tps-110-110.png',
sku: '38码',
amount: 0,
induction: {
a: 0,
b: 100
}
},
{
item: '拖鞋2',
img: 'https://img.alicdn.com/imgextra/i2/O1CN01wtSTlr28OmrVgPKQ9_!!6000000007923-2-tps-200-200.png',
sku: '35码',
amount: 123,
induction: {
a: 90,
b: 8
}
},

]
const cellProps = (rowIndex, colIndex) => {
if (rowIndex === 0 && colIndex === 0) {
return {
// take 3 rows's space
rowSpan: 2
};
}

};

const convertTableToExcel = (
id = undefined, // Fusion Table 的id
filterHeader = false, // 复制时是否滤掉表头
) => {
return new Promise((resolve, reject) => {
try {
let htmlString = document.getElementById(id).innerHTML
const filterDOM = (selector) => {
// 创建一个临时div元素
var tempDiv = document.createElement('div');
// 将HTML字符串赋值给临时div的innerHTML属性
tempDiv.innerHTML = htmlString;
// 使用querySelectorAll方法获取所有要过滤的元素,并将其从临时div中移除
tempDiv.querySelectorAll(selector).forEach(function (element) {
element.remove();
});
// 获取过滤后的HTML字符串
return tempDiv.innerHTML;
}
htmlString = filterDOM('.next-table-lock-left')
if (filterHeader) {
htmlString = filterDOM('thead')
}

console.log(htmlString)
const type = "text/plain";
const blob = new Blob([htmlString], { type });
const data = [new ClipboardItem({ [type]: blob })];

navigator.clipboard.write(data).then(
() => resolve(),
(error) => reject(error),
);
} catch (error) {
reject(error)
}
})
}
return (
<div>
<Button type="primary" onClick={() => convertTableToExcel('table1')} style={{ marginRight: 10 }}>复制</Button>
<Button type="primary" onClick={() => convertTableToExcel('table1', true)}>复制(不含表头)</Button>
<Table id="table1" dataSource={dataSource} cellProps={cellProps}>
<Table.Column title="商品" width={300} dataIndex="item" lock="left" />
<Table.ColumnGroup title="信息">
<Table.Column title="规格" width={200} dataIndex="sku" />
{/* <Table.Column title="图片" width={200} dataIndex="img" cell={(val) => <img src={val} />} /> */}
<Table.Column title="库存" width={200} dataIndex="amount" />
<Table.Column title="说明" width={200} dataIndex="induction" cell={(val) => {
return <div>
<div>全包:{val.a}%</div>
<div>半包:{val.b}%</div>
</div>
}} />

</Table.ColumnGroup>
</Table>
</div>
)
}

export default App

实际上核心代码就这几行

1
2
3
4
5
6
7
8
9
const htmlString = '' // 这里就是你要复制的东西
const type = "text/plain";
const blob = new Blob([htmlString], { type });
const data = [new ClipboardItem({ [type]: blob })];

navigator.clipboard.write(data).then(
() => resolve(),
(error) => reject(error),
);

2023-08-04 JavaScript统计字符串广义上的长度

就这一个函数就可解决,非常好用

1
2
3
4
5
6
7
8
9
10
function unicodeLengthIgnoreSequence(str) {
let segmenter = new Intl.Segmenter();
let segments = segmenter.segment(str);
return [...segments].length;
}

console.log(
'👪𠄘👨‍👩‍👧‍👦'.length,
unicodeLengthIgnoreSequence('👪𠄘👨‍👩‍👧‍👦'),
)

得到结果👇🏻

1
> 15 3

Hexo怎么部署到Cloudflare Pages、怎么绑定阿里云的域名

先注册并登录Cloudflare Pages的网址

https://pages.cloudflare.com/

点击左侧菜单栏的Workers 和 Pages,然后点击创建应用程序

点击 Pages,然后点击连接到Git

选择好自己的Hexo博客仓库以后,在这里填写构建命令和构建产物目录

点击自定义域后,输入自己想要自定义的域名,例如我是blog.xxx.xxx

然后点击开始CNAME设置

上图的名称对应阿里云的主机记录目标对应阿里云的记录值

然后去阿里云解析域名

解析完域名后,再回到cloudflare pages点击检查DNS记录就大功告成啦

Flutter 3.0首次运行时卡在"Running Gradle task assembleDebug"的解决办法

第一步

找到flutter sdk路径下的这个文件

flutter/packages/flutter_tools/gradle/flutter.gradle

打开,并找到这个位置

1
2
3
4
5
6
7
buildscript {
repositories {
google()
mavenCentral()
}
...
}

注释掉 google()mavenCentral() ,并更改为

1
2
3
4
5
6
7
8
9
10
buildscript {
repositories {
// google()
// mavenCentral()
maven { url 'https://maven.aliyun.com/repository/google' }
maven { url 'https://maven.aliyun.com/repository/jcenter' }
maven { url 'https://maven.aliyun.com/nexus/content/groups/public' }
}
...
}

第二步

找到当前工程路径下的这个文件

/android/build.gradle

和第一步一样,打开,并注释掉 google()mavenCentral()并更改

注意第二步有两处,所以要改两个地方

第三步

还是这个文件

/android/build.gradle

找到DEFAULT_MAVEN_HOST并替换为国内的镜像地址

1
2
3
4
5
class FlutterPlugin implements Plugin<Project> {
// private static final String DEFAULT_MAVEN_HOST = "https://storage.googleapis.com";
private static final String DEFAULT_MAVEN_HOST = "https://storage.flutter-io.cn";
...
}

基本上完成上面这三步,就可以运行如下命令尝试再次启动了

1
flutter clean
1
flutter run

什么?你还不行啊。。。我倒,接着往下看吧,真没想到你这么倒霉

第四步

有可能是第三步的镜像地址挂了,可以把第三步再改回来,咱们改host

打开这个网站 https://tool.chinaz.com/speedtest/storage.googleapis.com

获取你的能访问到的加速ip地址,改hosts

有好多个呢,你自己试试吧

1
2
3
4
5
# localhost name resolution is handled within DNS itself.
# 127.0.0.1 localhost
# ::1 localhost

142.251.43.16 storage.googleapis.com # 例如这样改,Mac和Linux不做介绍

再试试咯,不行就往下走

1
flutter clean
1
flutter run

第五步

到这基本上宣告你的gradle是死活下载不下来了,只能离线下载了,找到工程目录下的这个文件打开,找到里面的distributionUrl

/android/gradle/wrapper/gradle-wrapper.properties

1
2
...
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip

你看啊,我这里是gradle-7.5-all.zip

那就去访问gradle的离线下载网站吧,找到gradle-7.5-all.zip并且下载下来

https://services.gradle.org/distributions/

然后去系统的gradle存放目录替换掉死活下载不下来的那些东西

例如我是C:\Users\vear\.gradle\wrapper\dists\gradle-7.5-all\6qsw290k5lz422uaf8jf6m7co\gradle-7.5-all.zip

那就把C:\Users\vear\.gradle\wrapper\dists\gradle-7.5-all\6qsw290k5lz422uaf8jf6m7co下面的东西全删了

把新下载的gradle-7.5-all.zip拷贝进去

再回来试试咯,反正我是行了,你不行就只能另请高明了

1
flutter clean
1
flutter run

简单手写防抖节流

不多逼逼,直接上代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

export const debounce = (func: Function, timeout: number) => {
let timeoutList: Array<NodeJS.Timeout> = [];

return (...args: any[]) => {
let timeoutId: NodeJS.Timeout;
timeoutList.forEach(_timeoutId => clearTimeout(_timeoutId))
timeoutId = setTimeout(() => {
func(...args);
}, timeout);
timeoutList.push(timeoutId)
};
};



export const throttle = (func: Function, timeout: number) => {
let flag = true
return (...args: any[]) => {
if (flag) {
flag = false
setTimeout(() => {
func(...args);
flag = true
}, timeout);
}
};
};

域名访问失效?小心浏览器自动添加的 `www` 陷阱!

服务器明明已经配置了好了静态文件却无法访问是为什么

你是否精心配置好了服务器上的静态文件,满怀期待地在浏览器地址栏输入自己的一级域名(比如 example.com),结果却遭遇了冷冰冰的 “无法访问此网站” 错误?明明本地测试或通过其他方式访问 example.com 是正常的,为什么直接输入就不行了呢?别急着怀疑人生,问题很可能出在一个容易被忽视的细节上——现代浏览器对 www 前缀的自动补全行为。

现象:输入域名A,浏览器访问了域名B

简单来说:

  1. 你输入: example.com (一级域名)
  2. 浏览器实际访问: www.example.com (浏览器自动在域名前加上了 www!)

原因:Chromium内核的“贴心”特性

如今,绝大多数主流浏览器(Chrome、Edge、Brave、Opera、新版 Firefox 等)都基于 Chromium 内核。这个内核有一个设计初衷是方便用户的功能:**当用户直接在地址栏输入一个没有子域名部分的一级域名时,浏览器会尝试自动在它前面加上 www.**。

  • 输入 example.com -> 浏览器尝试访问 www.example.com

冲突点:服务器配置的局限性

问题就出在这里!你的服务器配置通常是这样的:

  • 你为 example.com 这个域名配置了静态文件服务或虚拟主机。当请求直接访问 example.com 时,服务器知道该去哪里找文件并正确响应。
  • 但是,你很可能没有为 www.example.com 做任何配置。 当浏览器自作主张地请求 www.example.com 时,服务器就懵了:
    • 它找不到为 www.example.com 配置的服务。
    • 或者,该域名指向了错误的目录或根本不存在。
    • 结果自然是服务器无法响应有效的页面,浏览器只能报错。

这就好比你把派对地址告诉了朋友是“公园路123号”(example.com),但朋友导航时却习惯性地输入了“公园路123号大厦”(www.example.com),而这个地方根本不存在或者大门紧锁。

解决方案:一劳永逸的 301 重定向

解决这个问题的核心思路很简单:**告诉服务器,所有访问 www.example.com 的请求,都应该自动、永久地跳转到 example.com**。这就是 301 永久重定向 的用武之地。

为什么是 301

  1. 用户友好:
    • 用户输入 example.com -> 浏览器尝试访问 www.example.com -> 服务器立即返回 301 状态码并指示:“永久搬家到 example.com 了,去那边!” -> 浏览器自动跳转到 example.com -> 成功加载内容。
    • 用户输入 www.example.com -> 同样被重定向到 example.com -> 成功访问。
    • 无论用户输入哪种形式,最终都能无缝抵达正确的 example.com
  2. SEO 优化: 301 重定向明确告诉搜索引擎(如 Google、Bing),www 版本是次要的或已废弃,所有权重、排名和索引都应集中在你的主域名 example.com 上,有效避免内容重复导致的 SEO 问题。

如何配置?

配置方法取决于你使用的 Web 服务器软件。下面以主流服务器 Nginx 配置为例:

Nginx 配置

在 Nginx 的配置文件中(通常在 /etc/nginx/sites-available//etc/nginx/conf.d/ 下,具体看你的配置),为 www.example.com 创建一个专门的 server 块:

server {
    listen 80;
    listen [::]:80;       # IPv6 监听
    server_name www.example.com;  # 捕获所有 www.example.com 的请求

    # 核心:301 永久重定向到无 www 的主域名
    return 301 http://example.com$request_uri;  # 保留原始请求的路径

    # 重要提示:如果站点已启用 HTTPS,应重定向到 HTTPS 版本!
    # return 301 https://example.com$request_uri;
}