diff --git a/_config.yml b/_config.yml index 1c24cd2..3bce407 100644 --- a/_config.yml +++ b/_config.yml @@ -1,24 +1,26 @@ # Site settings -title: LBX Blog -SEOTitle: 蜡笔熊的博客 | LBX Blog +title: ZhiyongXiao's Blog +SEOTitle: 肖志勇的Blog | XZY Blog header-img: img/home-bg-2.jpg -email: jinair1121@gmail.com -description: "这里是 @LBX蜡笔熊 的个人博客,与你一起发现更大的世界 | 要做一个有 swag 的程序员" -keyword: "蜡笔熊, LBX蜡笔熊, LBX, 蜡笔熊的博客, Lbx Blog, 博客, 个人网站, 互联网, Web, JavaScript, React, React Native, 前端, 设计" -url: "https://roselifetotj.github.io/" # your host, for absolute URL -baseurl: "" # for example, '/blog' if your blog hosted on 'host/blog' +email: skrhrba@Outlook.com +description: "这里是 @ZhiyongXiao 的个人博客,与你一起发现更大的世界" +keyword: +url: "https://zhiyong-xiao.github.io/" # your host, for absolute URL +baseurl: "" # for example, '/blog' if your blog hosted on 'host/blog' # Publish posts or collection documents with a future date. future: true # SNS settings -RSS: false -weibo_username: 那个踏浪来的仙女是我的 -zhihu_username: Roselife -github_username: labixiong +# RSS: false +weibo_username: ZhiyongXiao_pro +weread_usename: 桂影扶疏pro +Email_username: skrhrba@outlook.com +github_username: Zhiyong-Xiao +notion: https://deluxe-stick-0be.notion.site/17433e21324e80429e9cfb69596bd4e7?pvs=4 # twitter_username: huxpro # facebook_username: huxpro -# linkedin_username: firstname-lastname-idxxxx +# linkedin_username: first name-last name-id xxxx # Build settings # from 2016, 'pygments' is unsupported on GitHub Pages. Use 'rouge' for highlighting instead. @@ -35,7 +37,7 @@ exclude: "README.zh.md", ] anchorjs: true # if you want to customize anchor. check out line:181 of `post.html` -# If you have timezone issue (e.g. #68) in China, uncomment to use this: +# If you have time zone issue (e.g. #68) in China, uncomment to use this: #timezone: CN # Gems @@ -45,8 +47,8 @@ anchorjs: true # if you want to customize anchor. check out line:181 of `post.ht plugins: [jekyll-paginate] # Markdown settings -# replace redcarpet to kramdown, -# although redcarpet can auto highlight code, the lack of header-id make the catalog impossible, so I switch to kramdown +# replace red carpet to kramdown, +# although red carpet can auto highlight code, the lack of header-id make the catalog impossible, so I switch to kramdown # document: http://jekyllrb.com/docs/configuration/#kramdown markdown: kramdown kramdown: @@ -70,12 +72,12 @@ ba_track_id: bade937f1e77acfeb4fa77b726e60a98 # Google Analytics # ga_track_id: "UA-49627206-1" # Format: UA-xxxxxx-xx -# ga_domain: huangxuan.me +# ga_domain: huang xuan.me # Sidebar settings sidebar: true # whether or not using Sidebar. -sidebar-about-description: "我爱这生活。" -sidebar-avatar: img/avatar-lbx.jpg # use absolute URL, seeing it's used in both `/` and `/about/` +sidebar-about-description: "我爱自己故我在!" +sidebar-avatar: img/touxiang.jpg # use absolute URL, seeing it's used in both `/` and `/about/` # Featured Tags featured-tags: true # whether or not using Feature-Tags @@ -85,13 +87,13 @@ featured-condition-size: 1 # A tag will be featured if the size of it is more th chrome-tab-theme-color: "#000000" service-worker: true -# MathJax rendering for layout:page (e.g. post preview) +# MathJax rendering for layout: page (e.g. post preview) page-mathjax: false # Friends # friends: # [ -# { title: "乱序(Midare)", href: "http://mida.re/" }, +# { title: "notion·桂影扶疏", href: "https://www.notion.so/17433e21324e801b801cdcfc60074806?v=17433e21324e80cd84a5000cf812264e&pvs=4" }, # { title: "Ebn Zhang", href: "https://ebnbin.dev/" }, # { title: "Kun Qian", href: "http://kunq.me" }, # { title: "Sherry Woo", href: "https://sherrywoo.me/" }, diff --git a/_includes/about/en.md b/_includes/about/en.md index 96fc9dd..6a857d2 100644 --- a/_includes/about/en.md +++ b/_includes/about/en.md @@ -1,5 +1,7 @@ -Hey, I am labixiong, computer enthusiast. +Hey, my name is Xiao Zhiyong, 2025 graduate of Southern Medical University majoring in Public Utility Management (Hospital Management), undergraduate GPA 3.41/5.0. +- Honors: National Endeavor Scholarship, 2023 Guangzhou International Dragon Boat Invitational Champion, etc. +- Skills: CET-4, CET-6, NCRE Certificate of Level 2, Proficiency in SPSS and R, Putonghua Grade 2B. +- Email: skrhrba@outlook.com + -Graduated from both non-graduates, now living in Hangzhou, a front-end practitioner. - -Daily haunt on [Weibo](https://weibo.com/u/6324958995), [Zhihu](https://www.zhihu.com/people/roselife-4), [Bilibili](https://space.bilibili.com/687619573), [Github](https://github.com/labixiong), [Juejin](https://juejin.cn/user/3334169355356045), etc. +Daily haunt on [Weread](https://weread.qq.com/), [Bilibili](https://space.bilibili.com/1864771987?spm_id_from=333.1007.0.0), [Github](https://github.com/Zhiyong-Xiao), etc. diff --git a/_includes/about/zh.md b/_includes/about/zh.md index a695299..4d7b2c5 100644 --- a/_includes/about/zh.md +++ b/_includes/about/zh.md @@ -1,7 +1,9 @@ -Hey,我是蜡笔熊(labixiong),计算机狂热爱好者。 +Hey,我叫肖志勇,南方医科大学公共事业管理专业(医院管理方向)2025届毕业生,本科GPA 3.41/5.0。 -双非本科毕业,现居杭州,前端从业者。 +- 所获荣誉:国家励志奖学金、2023广州国际龙舟邀请赛冠军等 +- 掌握技能:CET-4、 CET-6、计算机二级、熟练使用SPSS和R语言、普通话二级乙等 +- Email: skrhrba@outlook.com -日常出没于[微博](https://weibo.com/u/6324958995)、[知乎](https://www.zhihu.com/people/roselife-4)、[B站](https://space.bilibili.com/687619573)、[Github](https://github.com/labixiong)、[掘金](https://juejin.cn/user/3334169355356045) 等。 +日常出没于[微信读书](https://weread.qq.com/)、[B站](https://space.bilibili.com/1864771987?spm_id_from=333.1387.0.0)、[Github](https://github.com/Zhiyong-Xiao)等。 diff --git "a/_posts/2017-02-15-Git\346\214\207\344\273\244\346\225\264\347\220\206.md" "b/_posts/2017-02-15-Git\346\214\207\344\273\244\346\225\264\347\220\206.md" deleted file mode 100644 index 1bf2443..0000000 --- "a/_posts/2017-02-15-Git\346\214\207\344\273\244\346\225\264\347\220\206.md" +++ /dev/null @@ -1,279 +0,0 @@ ---- -layout: post -title: Git指令整理 -subtitle: 不适合阅读的整理的一些个人常用的 Git 指令 -date: 2017-02-15 -author: LBX -header-img: img/post-bg-ios9-web.jpg -catalog: true -tags: - - Mac - - 终端 - - Git ---- - ->随便整理的一些自用的Git指令 - - -# GitHub创建仓库提示代码 - - echo "# 项目名" >> README.md - git init - git add README.md - git commit -m "first commit" - git remote add origin git@github.com:qiubaiying/项目名.git - git push -u origin master - -若仓库存在直接push - - git remote add origin git@github.com:qiubaiying/test.git - git push -u origin master - - -# 常用操作 - -#### 创建仓库(初始化) - 在当前指定目录下创建 - git init - - 新建一个仓库目录 - git init [project-name] - - 克隆一个远程项目 - git clone [url] - -#### 添加文件到缓存区 - - 添加所有变化的文件 - git add . - - 添加名称指定文件 - git add text.txt - -#### 配置 - - 设置提交代码时的用户信息 - git config [--global] user.name "[name]" - git config [--global] user.email "[email address]" - - -#### 提交 - 提交暂存区到仓库区 - git commit -m "msg" - - # 提交暂存区的指定文件到仓库区 - $ git commit [file1] [file2] ... -m [message] - - # 提交工作区自上次commit之后的变化,直接到仓库区 - $ git commit -a - - # 提交时显示所有diff信息 - $ git commit -v - - # 使用一次新的commit,替代上一次提交 - # 如果代码没有任何新变化,则用来改写上一次commit的提交信息 - $ git commit --amend -m [message] - - # 重做上一次commit,并包括指定文件的新变化 - $ git commit --amend [file1] [file2] ... - -#### 远程同步 - - # 下载远程仓库的所有变动 - $ git fetch [remote] - - # 显示所有远程仓库 - $ git remote -v - - # 显示某个远程仓库的信息 - $ git remote show [remote] - - # 增加一个新的远程仓库,并命名 - $ git remote add [shortname] [url] - - # 取回远程仓库的变化,并与本地分支合并 - $ git pull [remote] [branch] - - # 上传本地指定分支到远程仓库 - $ git push [remote] [branch] - - # 强行推送当前分支到远程仓库,即使有冲突 - $ git push [remote] --force - - # 推送所有分支到远程仓库 - $ git push [remote] --all - - - -#### 分支 - - # 列出所有本地分支 - $ git branch - - # 列出所有远程分支 - $ git branch -r - - # 列出所有本地分支和远程分支 - $ git branch -a - - # 新建一个分支,但依然停留在当前分支 - $ git branch [branch-name] - - # 新建一个分支,并切换到该分支 - $ git checkout -b [branch] - - # 新建一个分支,指向指定commit - $ git branch [branch] [commit] - - # 新建一个分支,与指定的远程分支建立追踪关系 - $ git branch --track [branch] [remote-branch] - - # 切换到指定分支,并更新工作区 - $ git checkout [branch-name] - - # 切换到上一个分支 - $ git checkout - - - # 建立追踪关系,在现有分支与指定的远程分支之间 - $ git branch --set-upstream [branch] [remote-branch] - - # 合并指定分支到当前分支 - $ git merge [branch] - - # 选择一个commit,合并进当前分支 - $ git cherry-pick [commit] - - # 删除分支 - $ git branch -d [branch-name] - - # 删除远程分支 - $ git push origin --delete [branch-name] - $ git branch -dr [remote/branch] - -#### 标签Tags - - 添加标签 在当前commit - git tag -a v1.0 -m 'xxx' - - 添加标签 在指定commit - git tag v1.0 [commit] - - 查看 - git tag - - 删除 - git tag -d V1.0 - - 删除远程tag - git push origin :refs/tags/[tagName] - - 推送 - git push origin --tags - - 拉取 - git fetch origin tag V1.0 - - 新建一个分支,指向某个tag - git checkout -b [branch] [tag] - -#### 查看信息 - - # 显示有变更的文件 - $ git status - - # 显示当前分支的版本历史 - $ git log - - # 显示commit历史,以及每次commit发生变更的文件 - $ git log --stat - - # 搜索提交历史,根据关键词 - $ git log -S [keyword] - - # 显示某个commit之后的所有变动,每个commit占据一行 - $ git log [tag] HEAD --pretty=format:%s - - # 显示某个commit之后的所有变动,其"提交说明"必须符合搜索条件 - $ git log [tag] HEAD --grep feature - - # 显示某个文件的版本历史,包括文件改名 - $ git log --follow [file] - $ git whatchanged [file] - - # 显示指定文件相关的每一次diff - $ git log -p [file] - - # 显示过去5次提交 - $ git log -5 --pretty --oneline - - # 显示所有提交过的用户,按提交次数排序 - $ git shortlog -sn - - # 显示指定文件是什么人在什么时间修改过 - $ git blame [file] - - # 显示暂存区和工作区的差异 - $ git diff - - # 显示暂存区和上一个commit的差异 - $ git diff --cached [file] - - # 显示工作区与当前分支最新commit之间的差异 - $ git diff HEAD - - # 显示两次提交之间的差异 - $ git diff [first-branch]...[second-branch] - - # 显示今天你写了多少行代码 - $ git diff --shortstat "@{0 day ago}" - - # 显示某次提交的元数据和内容变化 - $ git show [commit] - - # 显示某次提交发生变化的文件 - $ git show --name-only [commit] - - # 显示某次提交时,某个文件的内容 - $ git show [commit]:[filename] - - # 显示当前分支的最近几次提交 - $ git reflog - -#### 撤销 - - # 恢复暂存区的指定文件到工作区 - $ git checkout [file] - - # 恢复某个commit的指定文件到暂存区和工作区 - $ git checkout [commit] [file] - - # 恢复暂存区的所有文件到工作区 - $ git checkout . - - # 重置暂存区的指定文件,与上一次commit保持一致,但工作区不变 - $ git reset [file] - - # 重置暂存区与工作区,与上一次commit保持一致 - $ git reset --hard - - # 重置当前分支的指针为指定commit,同时重置暂存区,但工作区不变 - $ git reset [commit] - - # 重置当前分支的HEAD为指定commit,同时重置暂存区和工作区,与指定commit一致 - $ git reset --hard [commit] - - # 重置当前HEAD为指定commit,但保持暂存区和工作区不变 - $ git reset --keep [commit] - - # 新建一个commit,用来撤销指定commit - # 后者的所有变化都将被前者抵消,并且应用到当前分支 - $ git revert [commit] - - # 暂时将未提交的变化移除,稍后再移入 - $ git stash - $ git stash pop - -#### 其他 - - # 生成一个可供发布的压缩包 - $ git archives \ No newline at end of file diff --git "a/_posts/2017-02-16-Git-\344\273\243\347\240\201\345\233\236\346\273\232.md" "b/_posts/2017-02-16-Git-\344\273\243\347\240\201\345\233\236\346\273\232.md" deleted file mode 100644 index 9960ea6..0000000 --- "a/_posts/2017-02-16-Git-\344\273\243\347\240\201\345\233\236\346\273\232.md" +++ /dev/null @@ -1,63 +0,0 @@ ---- -layout: post -title: Git 代码回滚 -subtitle: 回滚代码的正确姿势 -date: 2017-02-16 -author: LBX -header-img: img/post-bg-debug.png -catalog: true -tags: - - Mac - - 终端 - - Git ---- - - ->并不适合阅读的个人文档。 - -# **git revert** 和 **git reset** 的区别 - 先看图: - -![](https://ww3.sinaimg.cn/large/006tNbRwgy1fcr9tu6vdjj30t30ez0y8.jpg) - -**sourceTree** 中 **revert** 译为**`提交回滚`**,作用为忽略你指定的版本,然后提交一个新的版本。新的版本中已近删除了你所指定的版本。 - -**reset** 为 **重置到这次提交**,将内容重置到指定的版本。`git reset` 命令后面是需要加2种参数的:`–-hard` 和 `–-soft`。这条命令默认情况下是 `-–soft`。 - -执行上述命令时,这该条commit号之 后(时间作为参考点)的所有commit的修改都会退回到git缓冲区中。使用`git status` 命令可以在缓冲区中看到这些修改。而如果加上`-–hard`参数,则缓冲区中不会存储这些修改,git会直接丢弃这部分内容。可以使用 `git push origin HEAD --force` 强制将分区内容推送到远程服务器。 - - -#### 代码回退 - -默认参数 `-soft`,所有commit的修改都会退回到git缓冲区 -参数`--hard`,所有commit的修改直接丢弃 - - $ git reset --hard HEAD^ 回退到上个版本 - $ git reset --hard commit_id 退到/进到 指定commit_id -推送到远程 - - $ git push origin HEAD --force - - -#### 可以吃的后悔药->版本穿梭 - -当你回滚之后,又后悔了,想恢复到新的版本怎么办? - -用`git reflog`打印你记录你的每一次操作记录 - - $ git reflog - - 输出: - c7edbfe HEAD@{0}: reset: moving to c7edbfefab1bdbef6cb60d2a7bb97aa80f022687 - 470e9c2 HEAD@{1}: reset: moving to 470e9c2 - b45959e HEAD@{2}: revert: Revert "add img" - 470e9c2 HEAD@{3}: reset: moving to 470e9c2 - 2c26183 HEAD@{4}: reset: moving to 2c26183 - 0f67bb7 HEAD@{5}: revert: Revert "add img" - -找到你操作的id如:`b45959e`,就可以回退到这个版本 - - $ git reset --hard b45959e - - - diff --git "a/_posts/2017-12-19-\344\270\272\345\215\232\345\256\242\346\267\273\345\212\240-Gitalk-\350\257\204\350\256\272\346\217\222\344\273\266.md" "b/_posts/2017-12-19-\344\270\272\345\215\232\345\256\242\346\267\273\345\212\240-Gitalk-\350\257\204\350\256\272\346\217\222\344\273\266.md" deleted file mode 100644 index 94666cf..0000000 --- "a/_posts/2017-12-19-\344\270\272\345\215\232\345\256\242\346\267\273\345\212\240-Gitalk-\350\257\204\350\256\272\346\217\222\344\273\266.md" +++ /dev/null @@ -1,125 +0,0 @@ ---- -layout: post -title: 为博客添加 Gitalk 评论插件 -subtitle: LBX Blog 添加 Gitalk 的评论插件了 -date: 2017-12-19 -author: LBX -header-img: img/post-bg-universe.jpg -catalog: true -tags: - - Blog ---- - - -## 前言 - -由于 **Disqus** 对于国内网路的支持十分糟糕,很多人反映 Disqus 评论插件一直加载不出来。而我一直是处于翻墙状态的~(话说你们做程序员的都不翻墙用Google的吗😅,哈哈,吐嘈下) - -针对这个问题,我添加了[Gitalk](https://github.com/gitalk/gitalk) 评论插件。在此,非常感谢 [@FeDemo](https://github.com/FeDemo) 的推荐 。 - -## 正文 - -### Gitalk 评论插件 - -首先来看看 Gitalk 的界面和功能: - -[![](https://ws4.sinaimg.cn/large/006tKfTcgy1fmm4u3j0lmj30nk0kl40i.jpg)](https://gitalk.github.io/) - -gitalk 使用 Github 帐号登录,界面干净整洁,最喜欢的一点是支持 `MarkDown语法`。 - -### 原理 - -Gitalk 是一个利用 Github API,基于 Github issue 和 Preact 开发的评论插件,在 Gitalk 之前还有一个 [gitment](https://github.com/imsun/gitment) 插件也是基于这个原理开发的,不过 gitment 已经很久没人维护了。 - -可以看到在 gitalk 的评论框进行评论时,其实就是在对应的 issue 上提问题。 - -![gitalk评论框](https://ws4.sinaimg.cn/large/006tKfTcgy1fmm5916av1j30i209rab7.jpg) - -![Github issue](https://ws4.sinaimg.cn/large/006tKfTcgy1fmm596ggkfj30mx0gfjuk.jpg) - - -### 集成 Gitalk - -到这里,你应该对 Gitalk 有个大致的了解了,现在,开始集成 gitalk 插件吧。 - - -将这段代码插入到你的网站: - - -```js - -{% if site.gitalk.enable %} - - - - -
- -{% endif %} - -``` - -我们需要关心的就是配置下面几个参数: - -```js -clientID: `Github Application clientID`, -clientSecret: `Github Application clientSecret`, -repo: `Github 仓库名`,//存储你评论 issue 的 Github 仓库名(建议直接用 GitHub Page 的仓库名) -owner: 'Github 用户名', -admin: ['Github 用户名'], //这个仓库的管理员,可以有多个,用数组表示,一般写自己, -id: 'window.location.pathname', //页面的唯一标识,gitalk 会根据这个标识自动创建的issue的标签,我们使用页面的相对路径作为标识 -``` -当然,还有其他很多参数,有兴趣的话可以 [ 点这里](https://github.com/gitalk/gitalk#options)。 - -比如我就增加了这个全屏遮罩的参数。 - -``` -distractionFreeMode: true, -``` - -### 创建 Github Application - -Gitalk 需要一个 **Github Application**,[点击这里申请](https://github.com/settings/applications/new)。 - -填写下面参数: - -![](https://ws1.sinaimg.cn/large/006tKfTcgy1fmm7jaib6fj30jo0gaacs.jpg) - -点击创建 - -获取 `Client ID` 和 `Client Secret` 填入你的我们 Gitalk 参数中 - -![](https://ws1.sinaimg.cn/large/006tKfTcgy1fmm7jrzff6j30lc0budhp.jpg) - -当你参数都设置好,将代码推送到 Github 仓库后,没什么问题的话,当你点击进入你的博客页面后就会出现评论框了。 - -当你用 github 帐号登录(管理员),并且第一次加载该会比较慢,因为第一次加载会自动在你 `repo` 的仓库下创建对应 issue。 - -比如说这样: - -![](https://ws2.sinaimg.cn/large/006tKfTcgy1fmm867n88cj30l809mjse.jpg) - -![](https://ws4.sinaimg.cn/large/006tKfTcgy1fmm8a0i0jkj30rr0ct42t.jpg) - -当然,你也可以手动创建issue作为 gitalk评论容器。只要有 `Gitalk` 标签 和 `id` 对应标签就可以。比我我自己创建的 [About issue](https://github.com/qiubaiying/qiubaiying.github.io/issues/38) 。 - -# 结语 - -最后说几句吐嘈几句, Gitalk 需要你点开每篇文章的页面才会创建对应的 issue,对我来说真是个糟糕的体验(文章有点多~)。 - -当然,也有解决办法,这篇 [自动初始化 Gitalk 和 Gitment 评论](https://draveness.me/git-comments-initialize),就解决了这个问题。 - -最后,[给个 star 吧](https://github.com/qiubaiying/qiubaiying.github.io)~ \ No newline at end of file diff --git "a/_posts/2023-07-16-http\350\257\267\346\261\202\345\244\264\345\217\212\345\261\236\346\200\247\345\200\274\346\225\264\347\220\206.md" "b/_posts/2023-07-16-http\350\257\267\346\261\202\345\244\264\345\217\212\345\261\236\346\200\247\345\200\274\346\225\264\347\220\206.md" deleted file mode 100644 index beeb451..0000000 --- "a/_posts/2023-07-16-http\350\257\267\346\261\202\345\244\264\345\217\212\345\261\236\346\200\247\345\200\274\346\225\264\347\220\206.md" +++ /dev/null @@ -1,827 +0,0 @@ ---- -layout: post -title: HTTP首部字段一览 -subtitle: 通用首部、请求首部、响应首部、实体首部 -date: 2023-07-16 -author: LBX -header-img: img/bg-material.jpg -catalog: true -tags: - - HTTP - - 前端 ---- - -**文档类文章,写的不算详细,后续会继续补充图片讲解、丰富文字描述,写这篇文章全程手写,用于加深个人记忆,期待您的star** - -HTTP协议的请求和响应报文中必定包含HTTP首部,只是平时在使用Web的过程中感受不到它。 - -### 目录 - -- 通用首部字段 -- 请求首部字段 -- 响应首部字段 -- 实体首部字段 - - -## 通用首部字段 - -| 首部字段名 | 说明 | -| -- | -- | -| Cache-Control | 控制缓存的行为 | -| Connection | 逐跳首部 | -| Date | 创建报文的日期时间 | -| Pragma | 报文指令 | -| Trailer | 报文末端的首部一览 | -| Transfer-Encoding | 指定报文主体 | -| Upgrade | 升级为其他协议 | -| Via | 代理服务器的相关信息 | -| Warning | 错误通知 | - -### Cache-Control - -> 通过指定该属性,操作缓存的工作机制 - -- public - -表明其他用户也可利用缓存 - -- private - -只以特定的用户作为对象,对于其他的用户发送过来的请求,代理服务器则不会返回缓存 - -- no-cache - -1. 客户端请求头中包含 - 表示客户端不会接收缓存过的响应,防止从缓存中返回过期的资源,缓存服务器会直接把请求转发给源服务器,进行有效期确认后处理资源 -2. 服务器响应头中包含 - ``` - Cache-Control: no-cache=Location - ``` - 如果响应头中有参数值则说明不进行缓存,如果没有值则可以进行缓存 - - -- no-store - -不进行缓存 - -- s-maxage - -``` -Cache-Control: s-maxage=1000 - -单位:秒 -``` - -s-maxage与max-age功能相同,不同点是s-maxage指定只适用于供多位用户使用的公共缓存服务器,对于同一用户重复返回响应的服务器来说,这个指令没有任何作用。 - -如果使用此指令,则忽略`Expires、max-age`首部 - -`extend: s-maxage与max-age的区别 -- max-age用于指定任何缓存(包括中间缓存)可以缓存资源的最长时间。s-maxage指定仅适用于共享缓存,例如代理服务器,用于指定共享缓存可以缓存资源的最长时间。max-age更多的是通过控制客户端缓存可以缓存资源的时间来优化web性能。虽然max-age仍有安全隐患` - -- max-age - -``` -Cache-Control: max-age=1000 -单位:秒 -``` -如果缓存时间数值比指定时间的数值更小,那么客户端就接收缓存的资源 -即:缓存时间没超过指定值就使用缓存 - -当值为0时,缓存服务器需要将请求转发给源服务器 - -HTTP/1.1版本中,max-age优先级高于Expires,HTTP/1.0中相反 - - -- max-stale - -``` -Cache-Control: max-stale=1000 -单位:秒 -``` -指示缓存资源,即使过期也照常接收 - -如果未指定参数值,那么无论经过多久,客户端都会接收响应 - -- min-fresh - -``` -Cache-Control: min-fresh=1000 -单位:秒 -``` -要求缓存服务器返回至少还未过指定时间的缓存资源 - -在这1000秒内如果有超过有效期的资源都无法作为响应返回 - - -- no-transform - -无论是在请求还是在响应中,缓存都不能改变实体主体的媒体类型,可防止缓存或代理压缩图片等类似操作 - -- only-if-cached - -要求缓存服务器不重新加载响应,也不会再次确认资源有效性,若发生请求缓存服务器的本地缓存无响应,则返回504 - -- must-revalidate - -代理服务器必须再次向源服务器确认验证资源有效性,如果无法连通源服务器再次获取有效资源的话,则必须给客户端返回一条504状态码 - -- proxy-revalidate - -代理服务器向客户端返回响应之前,必须再次验证缓存资源有效性 - ---- - -### Connection - -> 控制不再转发给代理的首部字段,管理持久化连接 - -- 不再转发给代理的首部字段 - -``` -Connection: 不再转发给代理的首部字段 -``` -在客户端发送请求和服务器返回响应内都可使用 - -- 管理持久化连接 - -HTTP/1.1中默认持久化连接,当服务器端想明确断开连接时,则指定属性值为close,如下 - -``` -Connection: close -``` - -在HTTP的旧版本中,默认不持久化连接,则需指定属性值为 Keep-Alive,如下 -``` -Connection: Keep-Alive -``` - -### Date - -> 表明创建HTTP报文的日期和时间 - -HTTP/1.1使用RFC1123中规定的日期时间的格式 -``` -Date: Tue, 03 Jul 2023 04:18:50 GMT -``` - -HTTP之前版本中使用RFC850中定义的格式 -``` -Date: Tue, 03-Jul-2023 04:18:50 GMT -``` - -还有一种格式,与C标准库中的asctime()函数的输出格式一致 -``` -Date: Tue, Jul 03 04:18:50 2023 -``` - -### Pragma - -> 历史遗留字段,仅作为与HTTP/1.0的向后兼容而定义 - -例如不接受过期缓存,直接使用`Cache-Control: no-cache`是最佳,但是掌握全部代理服务器的HTTP版本不太现实,所以为了更好的使用,需要同时指定`Pragma:no-cache`首部字段 - -### Trailer - -> 事先说明在报文主体后记录了哪些首部字段 - -``` -Trailer: Expires -``` - -在报文主体后会出现Expires首部 - -### Transfer-Encoding - -> 传输报文主体时采用的编码方式,HTTP/1.1的传输编码方式仅对分块传输编码有效 - -### Upgrade - -> 用于检测HTTP协议及其他协议是否可使用更高的版本进行通信,参数值可用来指定一个完全不同的通信协议 - - -### Via - -> 追踪客户端与服务器之间的请求和响应报文的传输路径 - -报文经过代理或网关时,会先在Via首部字段中附加该服务器的信息,然后再进行转发 - -``` -GET / HTTP/1.1 -Via: 1.0 代理服务器1, - 1.1 代理服务器2, - xxx -``` - -像上面所示,Via经过每个代理服务器会附加上服务器信息,前面的1.x为HTTP版本,后面为服务器信息,如果经过多个将以逗号隔开 - -Via首部经常与TRACE方法结合使用,用来追踪传输路径 - - -### Warning - -> 告知用户一些与缓存相关的问题的警告 - -格式如下: - -`Warning: [警告码] [警告的主机:端口号] "警告内容" [日期时间]` - -日期时间可省略 - ---- - -## 请求首部字段 - -> 客户端往服务端发送请求报文中所使用的字段,用于补充请求的附加信息、客户端信息、对响应内容相关的优先级等内容 - -| 首部字段名 | 说明 | -| -- | -- | -| Accept | 用户代理可处理的媒体类型 | -| Accept-Charset | 优先的字符集 | -| Accept-Encoding | 优先的内容编码 | -| Accept-Language | 优先的语言 | -| Authorization | Web认证信息 | -| Except | 期待服务器的特定行为 | -| From | 用户的电子邮箱地址 | -| Host | 请求资源所在服务器 | -| If-Match | 比较实体标记(ETag) | -| If-Modified-Since | 比较资源的更新时间 | -| If-None-Match | 比较实体标记(与If-Match相反) | -| If-Range | 资源未更新的发送实体Byte的范围请求 | -| If-Unmodified-Since | 比较资源的更新时间(与If-Modified-Since相反) | -| Max-Forwards | 最大传输逐跳数 | -| Proxy-Authorization | 代理服务器要求客户端的认证信息 | -| Range | 实体的字节范围请求 | -| Referer | 对请求中的URI的原始获取方 | -| TE | 传输编码的优先级 | -| User-Agent | HTTP客户端程序的信息 | - -### Accept - -> 通知服务器,用户代理能够处理的媒体类型及媒体类型的相对优先级 - -1. 媒体类型 - 文本类型:text/plain,text/html,text/css,application/json,application/xml,application/xhtml+xml...
- 图片类型:image/jpeg, image/gif, image/png...
- 音视频类型:video/mp4, video/mpeg, video/quicktime, audio/mp3...
- 应用程序使用的二进制文件:application/octet-stream, application/zip...
- - 这只是一小部分常见的类型,Accept值可以是[任何有效的MIME类型](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types) -2. 优先级处理 - 若想要给显示的媒体类型增加优先级,则使用q= 来额外表示权重,用分号隔开,值范围是0-1(可使用小数,精确到小数点后三位),默认为1 - `Accept: application/xml,text/html;q=0.8,*/*` */* 通配符 -- 表示接受所有类型的响应
- `Accept: application/xml;q=0.5,text/html;q=0.8` - -### Accept-Charset - -> 用于指定客户端能够接受的字符集编码。它允许客户端向服务器传递一个或多个字符集编码,也可指定优先级与Accept优先级规则一致 - -`Accept-Charset: iso-8859-5, unicode-1-1;q=0.8` - -常见属性: - -- UTF-8:Unicode字符集的一种编码方式,支持大部分国际语言字符。 -- ISO-8859-1:也被称为Latin-1,是ISO/IEC 8859标准定义的字符集编码,覆盖了西欧语言字符。 -- ISO-8859-2:也被称为Latin-2,是ISO/IEC 8859标准定义的字符集编码,覆盖了中欧和东欧语言字符。 -- Shift_JIS:日本的字符集编码,常用于日语文本。 -- EUC-KR:韩国的字符集编码,常用于韩语文本。 -- GB2312:中国的字符集编码,覆盖了简体中文字符。 -- Big5:繁体中文的字符集编码。 - -### Accept-Encoding - -> 用于指定客户端能够接受的内容编码方式。它允许客户端向服务器传递一个或多个内容编码方式,也可指定优先级与Accept优先级规则一致 - -`Accept-Encoding: gzip, deflate`
-`Accept-Encoding: *`
- -常见属性值 -- gzip:GNU zip压缩算法,常用于文本内容的压缩,可以显著减小传输的数据量。 -- deflate:使用zlib库进行压缩的算法,与gzip相似,但在一些情况下效果稍差。 -- br:Brotli压缩算法,是一种较新且高效的压缩算法,可以实现更好的压缩比。 -- identity:标识不使用任何内容编码,即不进行压缩或编码。 -- compress:UNIX系统中常用的压缩算法,已经很少使用。 -- 也可以使用 * 作为通配符,指定任意的编码格式 - -### Accept-Language - -> 用于指定客户端所能接受的自然语言,也可指定优先级与Accept优先级规则一致,[常见语言标识符](https://learn.microsoft.com/zh-cn/deployoffice/office2016/language/language-identifiers-optionstate-id-values) - -常见属性: -- en:英语(English)。 -- zh-CN:简体中文(中国大陆)。 -- zh-TW:繁体中文(台湾)。 -- ja:日语(Japanese)。 -- ko:韩语(Korean)。 -- de:德语(German)。 -- fr:法语(French)。 -- es:西班牙语(Spanish)。 -- ru:俄语(Russian)。 -- pt:葡萄牙语(Portuguese)。 - -每个语言标识符通常由一个主要语言和一个可选的地区/国家代码组成 - -### Authorization - -> 用来告知服务器用户代理的认证信息,提供身份验证凭据,允许客户端在访问受保护资源时提供身份验证信息,以验证其身份并获得授权 - -常见的属性: -- Basic: 基本身份验证(Basic Authentication) 是最常见的身份验证方式。credentials由用户名和密码组成,并经过base64编码的字符串。服务器收到这个凭据后,会解码并验证用户名和密码的有效性 -- Bearer: 用于OAuth2.0授权框架中的身份验证机制。token代表访问令牌(Access Token),用于授权访问受保护资源 -- Digest: 摘要身份验证(Digest Authentication)是一种安全的身份验证方式。在Authorization字段中,credentials包含一系列摘要信息,包括用户名、密码和其他安全参数。服务器使用这些信息与存储的凭据进行比较来验证身份 -- Token: 通用的令牌身份验证机制,其中token可以是任何类型的身份验证令牌,如JWT(JSON Web Token) -- ... - - -扩展: -[OAuth2.0](https://oauth.net/2/) -[JWT](https://jwt.io/) - -### Expect - -> 客户端告知服务器期望出现的某种特定行为,很多属性都已经被废弃,使用前还请查阅相关的规范和文档 - -常用属性: -- 100-continue: 当客户端发送包含大量数据的请求时,可以使用此属性。客户端在发送请求头部时,附带`Expect: 100-continue`字段,以通知服务器它期望收到一个100 Continue响应。如果服务器接受请求并愿意继续处理,它将发送一个100 Continue响应,然后客户端才会继续发送请求体 -- handshake: 在WebSocket握手期间,客户端可以使用此属性来指示服务器进行WebSocket握手。服务器收到此请求后,可以发送适当的响应以完成握手过程,简历WebSocket连接 -- trailer: 用于指示客户端期望在响应结束后收到一些附加的响应头部字段。服务器在发送响应正文后,可以发送一个包含附加头部字段的Trailer头部,以满足客户端的期望 -- continue: 类似于100-continue,它用于告知服务器客户端期望收到一个100 Continue响应。然而,这个属性在HTTP/1.1中已经被废弃 - -### From - -> 用来告知服务器使用用户代理的用户的电子邮箱地址 - -通常其使用的目的就是为了显示搜索引擎等用户代理的负责人的电子邮件练习方式 - -`From: jinair1121@163.com` - -### Host - -> 首部字段Host会告知服务器,请求的资源所处的互联网主机名和端口号,在HTTP/1.1规范内是唯一一个必须被包含在请求内的首部字段 - -一般情况下,请求中的主机名会用IP地址直接替换解决 - -但是如果相同的ip地址下部署运行着多个域名,那么服务器无法理解究竟是哪个域名对应的请求。此时就需要使用首部字段Host来明确指出请求的主机名,若服务器未设定主机名,那直接发送一个空值即可 - -### If-Match - -> 条件请求,用于指定一个或多个实体标签(ETag), 以便在服务器上进行资源更新操作时进行条件检查 - -客户端可以告知服务器,只有当资源的当前实体标签与请求中指定的实体标签匹配时,才执行请求的操作,如果不匹配,服务器返回412状态码,表示前提条件失败,并且请求不会执行 - -ETag表示实体标签,资源的唯一标识符,通常是由服务器生成的哈希值或版本号。在服务器响应请求时,通常会将当前资源的实体标签包含在ETag响应首部中。客户端发起更新操作时,将这个实体标签作为条件发送给服务器 - -- 匹配单个实体标签:`If-Match: "etag1"` -- 匹配多个实体标签:`If-Match: "etag1", "etag2", "etag3"` 只要匹配到其中一个,请求就会执行 -- 匹配任何实体标签:`If-Match: *` 无论资源的实体标签是什么,请求都会被执行,即无条件更新 - -If-Match首部通常与PUT或DELETE请求一起使用,用于确保在执行更新或删除操作之前,服务器上的资源仍然与客户端预期的相符。如果实体标签不匹配,服务器可以根据需要采取适当的操作,例如返回错误或忽略请求。 - -attention:如果请求中未包含If-Match首部,服务器将忽略条件检查,无论当前资源的实体标签是什么,请求都会被执行。此时,服务器可能会忽略潜在的并发更新问题,因此在关注资源的一致性和并发性时,使用If-Match首部是一个重要的实践。 - -### If-Modified-Since - -> 指定一个日期时间,只有当资源在指定日期时间之后被修改过,才会返回实际内容,否则返回304 Not Modified,表示资源未更改 - -`If-Modified-Since: Mon, 17 Jul 2023 22:04:23 GMT` - -获取资源的更新日期时间,可通过确认首部字段`Last-Modified`来确定 - -### If-None-Match - -> 与If-Match作用相反,用于指定If-None-Match字段值的实体标记(ETag)值与请求资源的ETag不一致时,它就告知服务器处理该请求 - -在GET或HEAD方法中使用此字段可获取最新的资源,与If-Modified-Since有些类似 - -匹配规则与If-Match一致(单个、多个、任意) - -### If-Range - -> 告知服务器若指定的If-Range的字段值(ETag值或时间)和请求资源的ETag值或时间一致时,作为范围请求处理。否则就返回全体资源。通常与Range头部一起使用 - -``` -If-Range: | HTTP-Date -``` - -- ETag - 字符串,代表与资源关联的实体标签。ETag是一个服务器为资源分配的唯一标识符,用于标记资源的版本。当资源发生变化时,ETag的值会随之改变,从而使客户端能够区分不同版本的资源 -- HTTP-Date - 遵循[RFC7231](https://datatracker.ietf.org/doc/html/rfc7231)日期规范,用于表示资源的最后修改时间,以便客户端可以根据资源的修改日期来判断是否需要重新获取资源。 - -服务器会根据字段值来判断是否满足条件,如果满足条件将返回整个资源,否则,如果资源未修改,则返回部分内容(206状态码);如果资源已修改,则服务器返回整个资源(200) - -使用If-Range头部可以在资源未修改的情况下避免重复传输整个资源,提高请求效率,尤其在使用Range头部请求部分资源时。 - -### If-Unmodified-Since - -> 与If-Modified-Since相反,作用是告知服务器指定的请求资源只有在字段值内指定的日期之后未发生更新的情况下,才能处理请求,如果发生了更新则返回412 - -``` -If-Unmodified-Since: HTTP-Date - -例:Tue, 18 Jul 2023 11:42:11 GMT -``` - -### Max-Forwards - -> 用于控制请求的转发次数。指示请求在通过代理服务器或网关时可以转发的最大次数。每经过一次代理服务器或网关,该值会减1,直到到0为止。当值为0时,代理服务器或网关应该停止转发请求,并返回响应 - -``` -Max-Forwards: number - -number: 一个正整数,表示可以转发的最大次数 -``` - -通常与TRACE方法一起使用。 - -防止请求在循环代理的网络中无限转发,从而避免请求的无线循环和资源浪费 - -### Proxy-Authorization - -> 用于在代理服务器上进行身份验证。用于在发送请求时提供代理服务器需要的凭据,以便访问目标资源。字段值通常使用Base64编码,将用户名和密码组合成一个字符串 - -``` -Proxy-Authorization: -``` -1. Basic:最常用,将用户名和密码进行base64编码,并在`Authorization`请求头中包含`Basic`关键字,后跟编码的凭据,例如`Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==`, Basic后面的字符串就是用户名和密码的编码。虽然经过编码,但是不是加密的形式,所以安全性较低,常用但不建议使用 - -2. Digest:在第一次请求时,客户端发送用户名和密码的摘要,然后在后续请求中使用生成的摘要来验证身份。避免了在请求中发送明文密码,提供了更好的安全性 - -3. NTLM:在windows系统上常用的身份验证机制。使用一系列挑战和响应来完成身份验证过程 - -4. Negotiate:指示客户端剋有通过NTLM或Kerberos进行身份验证。服务器将从客户端接收第一条请求,并根据支持的方案来选择相应的身份验证机制 - -5. Bearer: 用于OAuth2.0身份验证,客户端通过提供token来验证身份 - -6. AWS4-HMAC-SHA256:AWS(Amazon Web Services)使用的身份验证机制,基于签名版本4的哈希消息认证码(HMAC-SHA256) - -7. Custom: 自定义身份验证机制,有些代理服务器或系统可能支持 -### Range - -> 对于只需获取部分资源的范围请求,包含首部字段Range即可告知服务器资源的指定范围。 - -``` -语法:Range: bytes=first-byte-pos-last-byte-pos - -Range: bytes=5001-10000 // 请求获取从第5001字节至第10000字节的资源 -``` - -bytes是Range首部的唯一属性值,用于指定请求的资源范围。 - -接收到附带Range首部字段请求的服务器,会在处理请求之后返回状态码206 Partial Content。无法处理范围请求时,则返回状态码200 OK的响应及全部资源 - -### Referer - -> 正确的拼写应该是Referrer,告知服务器请求的原始资源的URI,当浏览器从一个页面跳转到另一个页面或发送请求时,会在头部包含该字段,告知服务器当前请求从哪个页面来的 - -``` -Referer: - -Referer: https://www.baidu.com/ -``` - -作用: -1. 统计分析:了解从哪些页面跳转过来的,从而分析流量来源和用户行为 -2. 防盗链:防止其他网站直接连接到本站 -3. SEO: 了解用户搜索来源,从而优化搜索结果的相关性 -4. 安全性检查:确保请求来自合法来源 - -有时候也会引发隐私和安全问题,因为Referer包含了用户正在访问的页面地址,可能泄露用户的隐私信息。因此在一些敏感或安全性较高的场景下,可能会采取措施限制或禁用Referer头部的发送 - -### TE - -> 告知服务器客户端能够处理响应的传输编码方式及相对优先级,用于传输编码 - -``` -TE: gzip, deflate;q=0.5 -``` - -除指定传输编码之外,还可以指定伴随trailer字段的分块传输编码的方式。应用后者时,只需把trailers赋值给该字段值 - -``` -TE: trailers -``` - -### User-Agent - -> 将创建请求的浏览器和用户代理名称等信息传达给服务器 - -由爬虫发起请求时,可能会在子段内添加爬虫作者的电子邮箱地址。此外,如果请求经过代理,那么中间也很可能被添加上代理服务器的名称 - -## 响应首部字段 - -> 由服务器向客户端返回响应报文中所使用的字段,用于补充响应的附加信息、服务器信息,以及对客户端的附加要求等信息。 - -| 首部字段名 | 说明 | -| -- | -- | -| Accept-Ranges | 是否接收字节范围请求 | -| Age | 推算资源创建经过时间 | -| ETag | 资源的匹配信息 | -| Location | 令客户端重定向至指定URI | -| Proxy-Authenticate | 代理服务器对客户端的认证信息 | -| Retry-After | 对再次发起请求的时机要求 | -| Server | HTTP服务器的安装信息 | -| Vary | 代理服务器缓存的管理信息 | -| WWW-Authenticate | 服务器对客户端的认证信息 | - -### Accept-Ranges - -> 用于指示服务器是否支持范围请求以及支持的范围单位。范围请求允许客户端仅请求资源的特定部分而不是整个资源 - -可指定的值有两种,可处理范围请求时指定其为bytes,反之指定其为none - -``` -Accept-Ranges: none | bytes -``` -none: 表示服务器不支持范围请求,客户端无法请求资源的特定部分,同时也将忽略请求头中的Range头部
-bytes:表示服务器支持范围请求,并且范围的单位是字节,响应中还可能包含`Content-Range`头部,用于指示返回内容的范围(bytes) - -对于大文件或资源的传输,分块下载,断点续传等功能非常有用。 - -### Age - -> 用于指示代理服务器或缓存中缓存的响应的时长,即响应在代理服务器或缓存中存在的时间 - -``` -Age: seconds // seconds表示响应在代理服务器或缓存中存在的时间,以秒为单位 - -Age: 600 // 这个缓存向源服务器确认过,已经过去了10分钟 -``` - -帮助客户端了解该响应在代理服务器或缓存中存储的时间。 - -通过判断Age的值来判断数据的新鲜程度,Age值越小说明越新,新获取的。Age值较大,则表示应在代理服务器或缓存中存在的时间较长,可能已经过期或不再是最新的 - -`attention: Age头部只在代理或缓存服务器中使用,并且只对缓存的响应起作用。原始服务器返回的响应不包含该头部` - -### ETag - -> 告知客户端实体标识。它是一种可将资源以字符串形式做唯一性标识的方式。 - -服务器会为每份资源分配对应的ETag值,资源更新时,ETag值也需要更新。生成ETag值时,并没有统一的算法规则,而是由服务器来分配 - -可以用作缓存验证机制,帮助客户端判断资源是否发生了变化,从而优化缓存策略和减少不必要的数据传输 - -``` -ETag: "opaque-string" -``` - -opaque-string: 不透明的字符串,用于标识资源的特定版本。这个字符串可以是资源内容的哈希值、版本号或任何能唯一标识资源版本的值 - -ETag的主要作用是在缓存机制中进行缓存验证。当客户端发送一个请求时,如果先前已经缓存了该资源,客户端会将之前返回的ETag值作为请求头If-None-Match的值,同时指示服务器客户端的缓存版本。服务器接收到请求后,将与当前资源的ETag值进行比较,如果匹配,则说明没有更改,返回304 Not Modified。如果不匹配,则说明发生变化,则返回新的资源内容,并在响应头中更新ETag值 - -- 强ETag - Strong ETag - - 完全匹配的标识符,表示资源的特定版本。当资源内容发生任何改变时,强ETag值也会响应地改变 - - ``` - ETag: "adc123" - ``` - -- 弱ETag - Weak ETag - - 一个可能不完全匹配的标识符,用于表示资源的特定版本。与强ETag不同,弱ETag的值可能在资源内容发生微小变化时不会改变。通常由服务器生成,并在头部返回,以带有`W/`前缀的引号字符串形式表示 - - ``` - ETag: W/"abc123" - ``` - 弱ETag的主要目的是在资源发生较小变化时提供缓存验证的灵活性。即使资源内容发生了某些变化,但这些变化可能是不重要的或者与缓存副本的差异很小,服务器仍然可以返回304 Not Modified,允许客户端继续使用缓存的版本 - -强ETag只有在完全匹配时才会返回304状态码,而弱ETag相对宽松,服务器可以根据自己的策略来决定是否返回304状态码 - -通常情况下,强ETag用于标识严格匹配的资源版本,而弱ETag用于标识部分匹配或灵活匹配的资源版本。 - -### Location - -> 用于指示客户端重定向的目标URL。将重定向的目标URL作为字段值,告知客户需要访问的新位置 - -基本上,该字段会配合3xx:Redirection的响应,提供重定向的URI - -使用场景: -- 网页跳转:当用户访问某个页面时,服务器可能根据不同条件将用户重定向到其他页面,例如登录成功之后跳转到首页 -- 资源移动:当资源的URL发生变化时,服务器可以使用Location头部将客户端重定向到新的资源位置 -- 错误处理:服务器可能在遇到错误或无效请求时,将客户端重定向到合适的错误页面,帮助用户更好地理解问题 -- RESTful API:在RESEful API中,服务器可能返回3xx状态码并在Location头部提供资源的URL,用于指示客户端创建的资源位置 - -### Proxy-Authenticate - -> 用于在代理服务器需要进行用户认证时,向客户端发送认证要求。 - -当代理服务器要求客户端提供有效的凭据来访问受保护的资源时,会添加此字段并指定认证方案(如基本认证、摘要认证等) - -``` -Proxy-Authenticate: authentication-scheme -``` - -authentication-scheme: 表示要认证方式的字符串,如"Basic", "Digest" - -客户端会尝试使用指定的认证方案,构造一个带有凭据的请求,并再次发送请求给代理服务器。客户端的认证请求头部通常是 `Proxy-Authorization` - -### Retry-After - -> 用于指示客户端在什么时间之后可以重新发送之前的请求。 - -当服务器无法立即处理请求或返回状态码 503 Service Unavailable(服务不可用)时,可以使用此头部告知客户端何时可以再次尝试请求 - -``` -Retry-After: date | seconds -``` - -date: 特定日期/时间的字符串 -seconds:整数,单位为秒 - -此头部通常用于指示服务的暂时不可用状态 - - -### Server - -> 告知客户端当前服务器上安装的HTTP服务器应用程序的信息,包含类型和版本等信息 - -``` -Server: server-name - -例:Server: Apache/2.2.17 (Unix) -``` - -作用: -- 识别服务器软件 -- 版本信息 -- 调试和故障排除 - -`attention: 可能存在潜在的安全风险,在生产环境中建议禁止` - -### Vary - -> 用于指示代理服务器和缓存如何根据请求头部中的字段来区分不同的缓存副本。 - -允许服务器通知代理服务器和缓存,在请求头部的特定字段值不同时,响应实体的内容也可能不同,因此需要分别缓存不同的副本 - -``` -Vary: header-field1, header-field2, ... -``` -header-field1, header-field2, ... 表示需要考虑的请求头部字段,这些字段的值会影响响应的内容 - -主要作用就是用来内容协商。服务器根据客户端的请求头部,选择合适的响应内容来返回。 - -例如客户端的 `Accept-Language` 头部,服务器可以返回不同的语言版本的内容。Vary将包含`Accept-Language`,以通知代理服务器和缓存,需要根据请求中的语言设置来区分缓存副本 - -### WWW-Authenticate - -> 用于在需要进行用户认证时,向客户端发送认证要求。 - -当服务器需要客户端提供有效的凭据(用户名和密码)来访问受保护的资源时,会添加此头部,并指定认证方案 - -状态码401 Unauthorized 响应中,肯定带有此字段 - -当服务器返回此响应头部时,客户端将在之后的请求中添加 `Authorization` 头部,并采用返回字段值的认证方式 - -## 实体首部字段 - -> 实体首部字段包含在请求报文和响应报文中的实体部分所使用的首部,用于补充内容的更新时间等与实体相关的信息 - -| 首部字段名 | 说明 | -| -- | -- | -| Allow | 资源可支持的HTTP方法 | -| Content-Encoding | 实体主体适用的编码方式 | -| Content-Language | 实体主体的自然语言 | -| Content-Length | 实体主体的大小(单位:字节) | -| Content-Location | 替代对应资源的URI | -| Content-MD5 | 实体主体的报文摘要 | -| Content-Range | 实体主体的位置范围 | -| Content-type | 实体主体的媒体类型 | -| Expires | 实体主体过期的日期时间 | -| Last-Modified | 资源的最后修改日期时间 | - - -### Allow - -> 用于指示对特定资源支持的HTTP方法 - -当服务器接收到不支持的方法时,返回405 Method Not Allowed状态码,同时还会把所有能支持的http方法写入首部字段Allow后返回 - -``` -Allow: method1, method2, ... - -Allow: GET, POST, PUT -``` -这些方法可以是标准的 HTTP 方法,如 GET、POST、PUT、DELETE,也可以是自定义的方法。 - -作用: -- 资源方式限制 -- 请求方法检查 - -### Content-Encoding - -> 指示服务器对响应实体进行了哪种类型的内容编码 - -常见的额内容编码类型:gzip、deflate、br、identity - -内容编码是指在不丢失实体信息的前提下所进行的压缩 - -`attention: 通常与Transfer-Encoding一起使用` - -### Content-Language - -> 指示响应实体的自然语言或语言集。 - -配合头部Accept-Language,进行内容协商 - -### Content-Length - -> 实体主体部分的大小,单位为字节 - -对实体主体进行内容编码传输时,不能再使用Content-Length。参考[RFC2616 4.4](https://datatracker.ietf.org/doc/html/rfc2616#section-4.4) - -### Content-Location - -> 提供了一个指示资源实际位置的URL - -用于标识HTTP响应中返回的实体的确切位置,可以与请求URI不同。在重定向或内容复制的情况下特别有用 - -``` -Content-Location: https://www.baidu.com/ -``` - -### Content-MD5 - -> 提供响应实体内容的MD5校验,MD5是一种常见的哈希算法,用于生成数据的唯一标识符,也被广泛用于验证数据的完整性 - -检查报文主体在传输过程中是否保持完整,以及确认传输到达 - -### Content-Range - -> 指定在HTTP请求或响应中传输的部分实体的范围。 - -它通常与HTTP请求中的Range头部字段或HTTP响应中的Accept-Ranges头部字段一起使用,以支持分段传输或断点续传的功能 - -``` -Content-Range: <单位> <起始字节位置>-<结束字节位置>/<总字节数> - -Content-Range: bytes 5001-10000/10000 -``` - -`attention: 只在响应中使用,不在请求中使用;必须严格遵守规范,以确保正确解析和处理范围信息,如果与请求的范围不匹配,则返回416,表示无法满足请求范围` - -### Content-Type - -> 用于指示HTTP消息中所传输的实体的MIME类型 - -MIME类型用于标识数据的性质和格式,以便接收方可以正确地处理数据 - -``` -Content-Type: <主类型>/<子类型> - -Content-Type: text/html -``` - -主类型:数据的主要类别,如文本、图像、音视频等 - -子类型:数据的具体子类别,进一步细分主类型,如纯文本、HTML、JPEG等 - -作用: -- 内容解析:根据字段值确定如何解析和处理接收到的数据 -- 数据格式指示:帮助接收方准确识别数据的格式,确保正确的数据解析和处理,避免出现数据损坏或意外结果 -- 协商内容:在一些情况下,用于内容协商 - -### Expires - -> 指定资源的过期时间。将资源失效的日期告知客户端 - -客户端在该时间之后,客户端不应再使用缓存的响应,而应向服务器发起新的请求以获取最新的资源 - -``` -Expires: - -Expires: Tue 18, Jul 2023 20:33:57 GMT -``` - -作用: - -- 服务器响应中使用Expires告知客户端,在过期时间之前,可以直接从本地缓存中获取资源,而不必再向服务器发送请求。 -- Expires字段允许服务器控制响应的有效时间。 - -HTTP/1.1中,此字段逐渐被取代,例如Cache-Control,提供了更灵活、更精确的缓存控制能力,能够更好地控制缓存的行为 - -`attention: 由于Expires使用的是GMT格式时间,可能导致客户端和服务器时钟不一致,进而导致时间不准确的问题,所以建议使用Cache-Control来替代Expires` - -当指定了Cache-Control:max-age时,比起首部字段Expires,会优先处理max-age - -### Last-Modified - -> 服务器上资源的最后修改时间,它表示资源的最后一次修改发生的日期和时间 - -``` -Last-Modified: - -Last-Modified: Tue 18, Jul 2023 20:43:57 GMT -``` -作用: -- 服务器会将资源的最后修改时间作为Last-Modified字段包含在响应中。客户端会将字段值保存起来,下次请求时将该值作为If-Modified-Since的值,向服务器发送请求 -- 该字段可以与ETag字段一起使用进行缓存协商,进行更精细的缓存控制和验证 - -HTTP/1.1中,提供了更先进的缓存机制Cache-Control和ETag - - -## 参考 -- [《图解HTTP》- 日 上野宣](https://www.ituring.com.cn/book/1229) -- [RFC2616](https://datatracker.ietf.org/doc/html/rfc2616), [RFC7231](https://datatracker.ietf.org/doc/html/rfc7231), [RFC850](https://datatracker.ietf.org/doc/html/rfc850), [RFC1123](https://datatracker.ietf.org/doc/html/rfc1123) -- [MDN MIME](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types) diff --git "a/_posts/2023-07-18-\345\274\272\347\274\223\345\255\230\345\222\214\345\215\217\345\225\206\347\274\223\345\255\230.md" "b/_posts/2023-07-18-\345\274\272\347\274\223\345\255\230\345\222\214\345\215\217\345\225\206\347\274\223\345\255\230.md" deleted file mode 100644 index 783b585..0000000 --- "a/_posts/2023-07-18-\345\274\272\347\274\223\345\255\230\345\222\214\345\215\217\345\225\206\347\274\223\345\255\230.md" +++ /dev/null @@ -1,63 +0,0 @@ ---- -layout: post -title: 强缓存和协商缓存 -subtitle: 了解缓存机制 -date: 2023-07-18 -author: LBX -header-img: img/bg-material.jpg -catalog: true -tags: - - HTTP - - 前端 ---- - -**浏览器会根据请求头`Expires`或者`Cache-Control: max-age`指定的时间来判断是否命中强缓存。如果命中了则直接加载缓存中的资源,请求并不会发送到服务器,返回200 OK状态码。** - -**如果未命中强缓存,浏览器会将请求发送给服务器,服务器来判断本地缓存是否有效,如果可以使用则不会返回资源,而是由浏览器从缓存中取出资源并返回,此时返回状态码304 Not Modified;如果未命中协商缓存,则服务器会将完整的资源返回给浏览器,浏览器获取到新资源,返回给用户,状态码200 OK,浏览器更新缓存** - -### 强缓存 - -说到强缓存,就不得不说的头部字段Expires/Cache-Control - -Expires: 实体主体过期的日期时间,`Expires: GMT格式` - -Cache-Control:max-age字段值,指定了实体主体会在多久后过期,单位为秒 - -Cache-Control: s-maxage字段值,与max-age作用相同 - -在http1.0中,`Expires: GMT格式`优先级高于`Cache-Control: max-age=10000`,在http1.1中相反,推荐使用Cache-Control指定控制缓存行为,因为Expires的字段值为GMT格式的日期,不准确 - -``` -http1.1中优先级顺序为:s-maxage > max-age > Expires -http1.0中优先级顺序为:Expires > s-maxage > max-age -``` - -max-age用于指定任何缓存(包括中间缓存)可以缓存资源的最长时间。s-maxage指定仅适用于共享缓存,例如代理服务器,用于指定共享缓存可以缓存资源的最长时间。max-age更多的是通过控制客户端缓存可以缓存资源的时间来优化web性能。虽然max-age仍有安全隐患 - -**总结:**推荐使用Cache-Control: max-age=xxx 来控制缓存过期时间 - -### 协商缓存 - -当没有命中强缓存,就会走协商缓存 - -协商缓存对应的头部信息 -- Last-Modified/If-Modified-Since -- ETag/If-None-Match - -Last-Modified和ETag均为响应头,If-Modified-Since和If-None-Match均为请求头 - -以下步骤不考虑是否命中强缓存: - -1. 当客户端像服务器首次发送请求的时候,服务器会返回Last-Modified(最后更新时间,GMT格式日期时间)和ETag(资源唯一标识符) -2. 再次进行请求,客户端在请求头中指定If-Modified-Since字段,字段值为服务器之前返回的Last-Modified字段值,If-None-Match请求头字段值为服务器之前返回的ETag响应头字段值 -3. 如果同时指定两个请求头,ETag比If-Modified-Since优先级要高,所以会首先判断客户端所请求资源的ETag值是否与请求头If-None-Match的字段值一致,如果一致的话,会在进行判断If-Modified-Since字段值,如果在指定日期之后被修改过,就会再次返回资源,状态码200 OK,如果没有被修改过,则返回304 Not Modified - - -流程图如下: - -![](https://github.com/labixiong/labixiong.github.io/blob/main/img/store/article/cache.png?raw=true) - -参考: -1. [http请求头整理](https://labixiong.github.io/2023/07/16/http%E8%AF%B7%E6%B1%82%E5%A4%B4%E5%8F%8A%E5%B1%9E%E6%80%A7%E5%80%BC%E6%95%B4%E7%90%86/) - - diff --git "a/_posts/2023-07-30-\345\277\253\351\200\237\346\220\255\345\273\272\344\270\252\344\272\272\345\215\232\345\256\242.md" "b/_posts/2023-07-30-\345\277\253\351\200\237\346\220\255\345\273\272\344\270\252\344\272\272\345\215\232\345\256\242.md" deleted file mode 100644 index 133c333..0000000 --- "a/_posts/2023-07-30-\345\277\253\351\200\237\346\220\255\345\273\272\344\270\252\344\272\272\345\215\232\345\256\242.md" +++ /dev/null @@ -1,328 +0,0 @@ ---- -layout: post -title: 快速搭建个人博客-详细版-2023 -subtitle: 手把手教你在半小时内搭建自己的个人博客 -date: 2023-07-19 -author: LBX -header-img: img/post-bg-re-vs-ng2.jpg -catalog: true -tags: - - Blog ---- - -> 正所谓前人栽树,后人乘凉。 -> -> 感谢[Huxpro](https://github.com/huxpro)提供的博客模板 -> 感谢[qiubaiying](https://github.com/qiubaiying)的博客总结 -> -> [我的博客](http://labixiong.github.io) - -# 前言 -Github Pages主要有什么作用呢 - -- 分享日常 -- 分享你的技术记录 -- github图床,存放自己的图片 - -踩坑的话倒是没踩什么坑,大家如果踩了什么坑,可以提在[我的博客项目](https://github.com/labixiong/labixiong.github.io)下提issues - -博客主页: - -![](https://github.com/labixiong/labixiong.github.io/blob/main/img/store/read-me/blog-home.png?raw=true) - -进入正文 - -# 快速开始 - -### 从注册一个Github账号开始 - -我采用的搭建博客的方式是使用 [GitHub Pages](https://pages.github.com/) + [jekyll](http://jekyll.com.cn/) 的方式。 - -要使用 GitHub Pages,首先你要注册一个[GitHub](https://github.com/)账号,GitHub 是全球最大的同性交友网站(吐槽下程序员~),你值得拥有。 - -### 拉取我的博客模板 - -注册完成后搜索 `labixiong.github.io` 进入[我的仓库](https://github.com/labixiong/labixiong.github.io) - - -![](https://github.com/labixiong/labixiong.github.io/blob/main/img/store/read-me/github-fork.png?raw=true) - -点击右上角的 **Fork** 将我的仓库拉倒你的账号下 - -稍等一下,点击刷新,你会看到**Fork**了成功的页面,仓库名下方会显示`forked from labixiong/labixiong.github.io` - - -### 修改仓库名 - -点击**settings**进入设置 - -![](https://github.com/labixiong/labixiong.github.io/blob/main/img/store/read-me/github.settings.png?raw=true) - - -这时你在在浏览器中输入 `你的Github账号名.github.io` 例如:`labixiong.github.io` - -这时候你的博客就会出现了,如果没出现的话可以等一会儿 - -若是出现 - -![](http://upload-images.jianshu.io/upload_images/2178672-cfd55a22902a9d2c.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -则需要 [检查一下你的仓库名是否正确](#Rename) - -### 整个网站结构 - -修改Blog前我们来看看Jekyll 网站的基础结构,当然我们的网站比这个复杂。 - -``` -├── _config.yml -├── _doc -| ├── Manual.md -| └── README.zh.md -├── _drafts -| ├── xxx -| └── xxx -├── _includes -| ├── footer.html -| └── header.html -├── _layouts -| ├── default.html -| └── post.html -├── _posts -| ├── 2023-07-18-xxx.md -| └── 2023-07-19-xxx.md -├── _data -| └── xxx -├── _site -├── img -└── index.html -``` - -其中重要的几个文件: - -- `_config.yml` 全局配置文件 -- `_posts` 放置博客文章的文件夹 -- `img` 存放图片的文件夹 - -一个基本的[jekyll站点通常是这样的](http://jekyll.com.cn/docs/structure/) - - - -### 修改博客配置 - -来到你的仓库,找到`_config.yml`文件,这是网站的全局配置文件。 - -点击修改 - -然后编辑`_config.yml`的内容 - -接下来我们来详细说说以下配置文件的内容: - -#### 基础设置 - -``` -# Site settings -title: You Blog Title #你博客的标题 -SEOTitle: 你的博客 | You Blog #显示在浏览器上搜索的时候显示的标题 -header-img: img/post-bg.jpg #显示在首页的背景图片 -email: You@gmail.com #邮箱 -description: "You Blog" #网站介绍 -keyword: "LBX, LBX Blog, 蜡笔熊的博客, labixiong, 蜡笔熊" # 关键词 -url: "https://labixiong.github.io" # 这个就是填写你的博客地址 -baseurl: "" # 这个不用填写 - -``` -#### 侧边栏 - -``` -# Sidebar settings -sidebar: true # 是否开启侧边栏. -sidebar-about-description: "说点装逼的话。。。" -sidebar-avatar:/img/avatar-by.JPG # 你的个人头像 这里你可以改成我在img文件夹中的两张备用照片 img/avatar-m 或 avatar-g -``` -#### 社交账号 -展示你的其他社交平台 - -![](http://upload-images.jianshu.io/upload_images/2178672-ec775a22f76e2f40.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - -在下面你的社交账号的用户名就可以了,若没有可不用填 - -``` -# SNS settings -RSS: false -weibo_username: username -zhihu_username: username -github_username: username -facebook_username: username -``` - - -#### 评论系统 - - -博客中使用的是 [Disqus](https://disqus.com/) 评论系统,在 [官网](https://disqus.com/) 注册帐号后,按下面的步骤简单的配置即可: - -进入 [设置页面](https://disqus.com/home/settings/profile/) 配置个人信息 - -![配置 Disqus 个人信息](https://github.com/labixiong/labixiong.github.io/blob/main/img/store/article/disqus-profile.png?raw=true) - -找到 **Username** - -![Disqus Account](https://github.com/labixiong/labixiong.github.io/blob/main/img/store/article/disqus-account.png?raw=true) - -这个 **Username** 就是我们 `_config.yml` 中 `disqus_username` - -``` -# Disqus settings(https://disqus.com/) -disqus_username: dcjin -``` - -> 很对人反映 Disqus 评论插件加载不出来,因为 Disqus 在国内加载缓慢,所以我新集成了 Gitalk 评论插件(感谢[@FeDemo](https://github.com/FeDemo)的推荐),喜欢折腾的朋友可以看这篇:[《为博客添加 Gitalk 评论插件》](http://qiubaiying.top/2017/12/19/%E4%B8%BA%E5%8D%9A%E5%AE%A2%E6%B7%BB%E5%8A%A0-Gitalk-%E8%AF%84%E8%AE%BA%E6%8F%92%E4%BB%B6/)。 我已经在`_config.yml` 配置就好了,只需要填写参数可以了。 - -#### 网站统计 - -集成了 [Baidu Analytics](http://tongji.baidu.com/web/welcome/login) 到各个网站注册拿到track_id替换下面的就可以了 - -拿[百度统计](https://www.tongji.baidu.com/)来进行示例: - -![](https://github.com/labixiong/labixiong.github.io/blob/main/img/store/article/baidutongjisetting.png?raw=true) - -![](https://github.com/labixiong/labixiong.github.io/blob/main/img/store/article/baidutongjicode.png?raw=true) - -也可以使用谷歌统计进行分析,这里就不进行举例了 - -若不想启用统计,直接删除或注释掉就可以了 - -``` -# Analytics settings -# Baidu Analytics -ba_track_id: 83e259f69b37d02a4633a2b7d960139c - -# Google Analytics -ga_track_id: 'UA-90855596-1' # Format: UA-xxxxxx-xx -ga_domain: auto -``` - -#### 好友 - -``` -friends: [ - { - title: "简书·BY", - href: "http://www.jianshu.com/u/e71990ada2fd" - },{ - title: "Apple", - href: "https://apple.com" - },{ - title: "Apple Developer", - href: "https://developer.apple.com/" - } -] -``` - -#### 保存 -如果是在github网站直接编辑`_config.yml`文件的话,将网页拉倒底部,点击 `Commit changes` 提交保存,这样的话连git都不用安装 - -如果是clone到本地的话,使用git进行提交就行了。 - -至此就算配置完成了。 - -# 写文章 - -## 创建 -文章统一放在网站根目录下的 `_posts` 的文件夹中。 - -![](https://github.com/labixiong/labixiong.github.io/blob/main/img/store/article/post-example.png?raw=true) - -创建一个文件 - -![](https://github.com/labixiong/labixiong.github.io/blob/main/img/store/article/post-new-file.png?raw=true) - -文章内容有好几种布局,可以任意选择一种 - -```markdown ---- -layout: post # 文章布局 page post keynote default -title: 强缓存和协商缓存 # 文章标题 -subtitle: 了解缓存机制 # 副标题 -date: 2023-07-18 # 文章日期 -author: LBX # 文章作者 -header-img: img/bg-material.jpg # 头部图片 -catalog: true # 是否显示目录 -tags: # 文章标签 - - HTTP - - 前端 ---- - -### 内容 -xxx - -``` - -按格式创建文章后,提交保存。进入你的博客主页,新的文章将会出现在你的主页上. - -你已经成功搭建了自己的个人博客以及学会在博客上撰写文字的技能了。 - - -#### 首页标签 - -在首页可以看到这些特色标签,当你的文章出现相同标签(默认相同的**标签数量大于1**),才会自动生成。 - -所以当你只放一篇文章的时候是不会出现标签的。 - -![](http://upload-images.jianshu.io/upload_images/2178672-9281b7176c456f92.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240) - - -建站的初期,博客比较少,若你想直接在首页生成比较多的标签。你可以在 `_congfig.yml`中找到这段: - -``` -# Featured Tags -featured-tags: true # 是否使用首页标签 -featured-condition-size: 1 # 相同标签数量大于这个数,才会出现在首页 -``` - -将其修改为`featured-condition-size: 0`, 这样只有一个标签时也会出现在首页了。 - -相反,当你博客比较多,标签也很多时,这时你就需要改回 `1` 甚至是 `2` 了。 - -# 本地运行博客 -- windows系统为例 - -## 先行下载Ruby - -[下载地址](https://rubyinstaller.org/downloads/), 我下载的是最新的版本 - -## 操作 - -安装了ruby之后,可以 `cmd + r` 组合键,输入cmd进入windows终端 - -1. 输入 `ruby -v` 查看ruby版本,确定是否安装成功 - -2. 输入`gem -v` 查看gem版本,确认gem是否安装成功 - -3. 接着输入`gem install bundler` 安装bundler - -4. 接着找到文件夹中clone下来的项目文件夹,右键点击文件夹,选择`git bash here` 打开终端 - - 前置条件:需要先安装[git](https://git-scm.com/downloads) - - - ![](https://github.com/labixiong/labixiong.github.io/blob/main/img/store/article/git-downloads.png?raw=true) - - - ![](https://github.com/labixiong/labixiong.github.io/blob/main/img/store/article/git-download-standable.png?raw=true) - - - 点击下载好的文件,进行安装,一路点击next默认安装即可 - -5. 打开终端之后,输入`bundler install` 进行安装依赖 -6. 安装以来完成后,会多出一个 `Gemfile.lock`文件,接着再输入 `bundler exec jekyll serve` 运行博客项目 -7. 运行完毕后会出现一个地址,打开地址即可 下图中Server address一栏就是本地运行的项目地址 - - ![](https://github.com/labixiong/labixiong.github.io/blob/main/img/store/article/bundler-install.png?raw=true) - -# 参考 - -- [Huxpro的博客](https://github.com/huxpro/huxpro.github.io) -- [qiubaiying的博客](https://github.com/qiubaiying/qiubaiying.github.io) -- [qiubaiying的博客搭建教程的wiki](https://github.com/qiubaiying/qiubaiying.github.io/wiki/%E5%8D%9A%E5%AE%A2%E6%90%AD%E5%BB%BA%E8%AF%A6%E7%BB%86%E6%95%99%E7%A8%8B) - - - - - diff --git "a/_posts/2023-08-01-\350\260\210\350\260\210axios.md" "b/_posts/2023-08-01-\350\260\210\350\260\210axios.md" deleted file mode 100644 index e793d53..0000000 --- "a/_posts/2023-08-01-\350\260\210\350\260\210axios.md" +++ /dev/null @@ -1,762 +0,0 @@ ---- -layout: post -title: 谈谈axios -subtitle: axios为何被广泛使用,有什么优势?如何封装,从ajax谈起 -date: 2023-08-01 -author: LBX -header-img: img/bg-little-universe.jpg -catalog: true -tags: - - 前端 - - axios ---- - -> axios为何被广泛使用,与fetch及其他网络请求库的区别,有什么优势?如何封装,简单原理了解,从ajax谈起 - -## 简单了解ajax - -为什么会出现? - -传统的网页如果需要更新内容的话,必须重载整个页面,例如提交表单场景,然后在新页面告诉你操作是成功了还是失败了。如果碰到网速太慢或其他原因,就会得到一个404的页面了。所以ajax的出现大大改变了这种现状,可以局部刷新页面,用户体验感提升,较少网络数据的传输量,同时也节省网络带宽。 - -> 语义:Asynchronous JavaScript and XML(异步的 JavaScript 和 XML),它不是新的变成语言,而是一种使用现有标准的新方法,在不重新加载整个页面的情况下,局部更新部分页面 - -- 工作原理 - - 在用户和服务器之间加了一个中间层(AJAX引擎),使用户操作与服务器响应异步化 - -- 创建对象 - - ```js - const xhr = new XMLHttpRequest() // xhr即为ajax实例 - - // 旧版本的ie ie5 ie6 使用ActiveX对象 - const xhr = new ActiveXObject("Microsoft.XMLHTTP"); - ``` - -- 请求 - - 向服务器发送请求,使用实例对象的open和send方法 - - ```js - /** - open方法的三个参数: - method -- 请求类型 GET POST PUT DELETE OPTIONS TRACE等皆可 - url -- 请求资源位置 - async -- 布尔类型 true代表异步 false代表同步 - - 对于post请求时,send可以携带body参数 例如:xhr.send('name=zs&age=18') - - get请求时参数可以直接写到open方法url参数用问号拼接 例如:xhr.open("GET", "xxx.txt?name=zs", true) - - setRequestHeader -- 设置请求头,两个参数,第一个为请求头键名 第二个为请求头的值 - */ - xhr.open("GET", "xxx.txt", true) - - xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded"); - - // 发送给服务器 - xhr.send() - ``` - -- 响应 - - responseText -- 获得字符串形式的响应数据 只有当 readyState 属性值变为4时,responseText 属性才可用 - - responseXML -- 获得XML形式的响应数据 如果来自服务器的响应是 XML,而且需要作为 XML 对象进行解析 - -- onreadystatechange事件 - - 当发送一个请求后,客户端需要确定请求什么时候完成,此事件就是用来捕获请求状态 - - 每当readyState改变时,都会触发此事件 - - ```js - xhr.onreadystatechange = function() { - if (xhr.readyState === 4 && xhr.status === 200) { - console.log(xhr.responseText); - } - } - ``` - - readyState的取值 - - - 0 -- 请求未初始化,还没有调用open方法 - - 1 -- 服务器连接已建立,但没有发送,没有调用send方法 - - 2 -- 请求已接收 - - 3 -- 请求处理中 - - 4 -- 请求已完成,且响应就绪 - - status http状态码 - ---- - -## 了解axios - -> 基于promise的请求库,作用于nodejs和浏览器中,同构应用程序(即同一套代码可以运行在浏览器和nodejs中),在服务器端使用nodejs的http模块,在客户端使用XMLHttpRequests - -- 特点 - - 1. 支持Promise api - 2. 转换请求和响应数据 - 3. 取消请求 - 4. 超时处理 - 5. 自动将请求序列化 - 6. 自动转换JSON数据 - ... - -- 基本用法 - - ```js - // 采用ES Modules方法引入,作为举例 - - // 安装,以下三种方式皆可 - npm install axios / bower install axios / yarn add axios - - // 也可CDN引入 - - - // 引入 - import axios from 'axios' - - // 请求 - // 向给定ID的用户发起请求 - axios.get('/user?ID=12345').then(function (response) { - // 处理成功情况 - console.log(response); - }) - - // 也可采用config对象的形式 - axios({ - method: 'post', - url: '/user/12345', - data: { - firstName: 'Fred', - lastName: 'Flintstone' - } - }) - ``` - -- axios实例 - - 关于创建实例的参数, 以最新版本的axios(v1.4.0)为例 - ```ts - // 请求的服务器URL - url?: string; - - // 创建请求时使用的方法 get delete head options post put patch purge link unlink中的一种,大小写都可 - method?: Method | string; - - // 为axios实例传递相对URL,自动拼接到请求路径前 - baseURL?: string; - - // 允许在向服务器发送之前,修改请求数据,只能用于put post patch这几个请求方法 - // 数组中最后一个函数必须返回一个字符串,一个Buffer实例,ArrayBuffer,FormData或Stream - // 可以修改请求头 - // 参数为data, headers - transformRequest?: AxiosRequestTransformer | AxiosRequestTransformer[]; - - // e.g. - transformRequest: [ - function (data, headers) { - // 对发送的数据进行任意转换处理 - return data - } - ] - - - // 在传递给 then/catch 前,允许修改响应数据 对接收的数据进行任意处理 - transformResponse?: AxiosResponseTransformer | AxiosResponseTransformer[]; - - // e.g. - transformResponse: [ - function(data) { - - // 对接收的数据进行任意转换处理 - return data - } - ] - - // 请求头 - headers?: (RawAxiosRequestHeaders & MethodsHeaders) | AxiosHeaders; - - // 参数,params的参数会出现在url path中 - params?: any; - - // 用于序列化params - paramsSerializer?: ParamsSerializerOptions | CustomParamsSerializer; - - // 请求body参数,该方式传的参数出现在 Request Payload中,即body中 - data?: D; - - // 请求时间限制 - timeout?: Milliseconds; - - // 请求超时提示错误信息 - timeoutErrorMessage?: string; - - // 跨域请求时是否需要使用凭证 - withCredentials?: boolean; - - // 允许自定义处理请求,使测试更加容易 - // 返回一个promise并提供一个有效的响应 - // 例子:https://github.com/axios/axios/blob/v1.x/lib/adapters/README.md - adapter?: AxiosAdapterConfig | AxiosAdapterConfig[]; - - // HTTP Basic Auth - auth?: AxiosBasicCredentials = { - username: string; - password: string; - }; - - // 响应类型 arraybuffer blob document json text stream - responseType?: ResponseType; - - // 解码响应的编码 默认值为utf8 - // ascii ansi binary base64 base64url hex latin1 ucs-2 ucs2 utf-8 utf8 utf16le 以上编码还可以转换为大写传入 - responseEncoding?: responseEncoding | string; - - // xsrf token 的值,被用作 cookie 的名称 - xsrfCookieName?: string; - - // 带有 xsrf token 值的http 请求头名称 - xsrfHeaderName?: string; - - // 允许为上传处理进度事件 -- 浏览器专属 - onUploadProgress?: (progressEvent: AxiosProgressEvent) => void; - - // 允许为下载处理进度事件 -- 浏览器专属 - onDownloadProgress?: (progressEvent: AxiosProgressEvent) => void; - - // AxiosProgressEvent 的定义 - export interface AxiosProgressEvent { - loaded: number; - total?: number; - progress?: number; - bytes: number; - rate?: number; - estimated?: number; - upload?: boolean; - download?: boolean; - event?: BrowserProgressEvent; - } - - - // 定义了node.js中允许的HTTP响应内容的最大字节数 - maxContentLength?: number; - - // 验证响应状态 2xx 3xx 4xx 5xx等 返回一个布尔值 - validateStatus?: ((status: number) => boolean) | null; - - // (仅Node)定义允许的http请求内容的最大字节数 - maxBodyLength?: number; - - // 定义了在node.js中要遵循的最大重定向数 如果值为0 则不进行重定向 - maxRedirects?: number; - - // 最大上传下载速率 - maxRate?: number | [MaxUploadRate, MaxDownloadRate]; - - // 重定向之前处理 - beforeRedirect?: (options: Record, responseDetails: { headers: Record }) => void; - - // 定义了在nodejs中使用的unix套接字 - // e.g. '/var/run/docker.sock' 发送请求到 docker 守护进程。 - // 只能指定socketPath或proxy,如果都指定,则使用socketPath - socketPath?: string | null; - transport?: any; - - // 定义执行http时要使用的自定义代理和https请求 - httpAgent?: any; - httpsAgent?: any; - - // false禁用代理 - // 为对象时,host port为必填 - proxy?: { - host: string; - port: number; - auth?: { - username: string; - password: string; - }; - protocol?: string; - }; - - // 取消请求 - cancelToken?: CancelToken; - - // 是否应该自动地压缩响应正文,如果设置为true还将删除 content-encoding 头部字段 - decompress?: boolean; - - // 属性均为非必填 - // silentJSONParsing -- 不进行json格式化 forcedJSONParsing -- 被迫进行json格式化 clarifyTimeoutError -- 声明超时错误 - transitional?: TransitionalOptions = { - silentJSONParsing?: boolean; - forcedJSONParsing?: boolean; - clarifyTimeoutError?: boolean; - }; - - // 信号,用来配合取消请求使用 - signal?: GenericAbortSignal = { - readonly aborted: boolean; - onabort?: ((...args: any) => any) | null; - addEventListener?: (...args: any) => any; - removeEventListener?: (...args: any) => any; - }; - - // 不安全的http解析 - insecureHTTPParser?: boolean; - - // 环境 - env?: { - FormData?: new (...args: any[]) => object; - }; - - // 表单序列化 - formSerializer?: FormSerializerOptions = { - visitor?: (value, key, path, helpers) => { - // helpers = { - // defaultVisitor: { visitor, dots, metaTokens, indexes }; -- 等同于当前对象 - // convertValue: (value: any) => any; - // isVisitable: (value: any) => boolean; - // } - - return true - }; - dots?: boolean; - metaTokens?: boolean; - indexes?: boolean | null; - }; - - // 家族成员 - family?: 4 | 6 | undefined; - - // 查找 - lookup?: ((hostname: string, options: object, cb: (err: Error | null, address: string, family: number) => void) => void) | - ((hostname: string, options: object) => Promise<[address: string, family: number] | string>); - ``` - - 常见创建实例方法 - ```js - const service = axios.create({ - baseURL: 'http://localhost:8080/', - timeout: 10000 - }) - ``` - -- 请求配置 -- 与创建实例时参数相同 - - ```js - // 两种写法皆可 - // 1. - export const getData = (params) => { - return service.get('/api/getData', params) - } - - // 2. - export function getData(params) { - return service({ - url: '/api/getData', - method: 'get', - params - }) - } - - // 使用时常见的两种方式 - import { getData } from 'xxx' - - import * as api from 'xxx' - ``` - -- 响应结构 - - ```js - { - // 由服务器提供的响应 - data: { - message: '', - code: 200, - data: {} - }, - - // 服务器响应的http状态码 - status: 200, - - // 服务器响应的http状态信息 - statusText: 'OK', - - // 服务器响应头,所有的header名称都是小写,可以使用方括号形式访问 - // response.headers['content-type'] - headers: { - // 键值对形式 - cache-control: 'no-cache', - content-type: 'application/json', - ... - }, - - // axios请求的配置信息 - config: { - // 配置信息 - baseURL: '', - method: '', - timeout: '', - ... - }, - - // 生成此响应的请求,在nodejs中它是最后一个ClientRequest实例 - // 在浏览器中则是XMLHttpRequest实例 - request: { - // 请求信息 - readyState: 4, - status: 200, - timeout: 300000, - ... - } - } - ``` - -- 拦截器 - -> 在请求发送前和响应接收前的操作可以在拦截器中进行,可以给axios自身或者axios实例添加 - - ```js - // 返回一个id,方便使用eject方法清除拦截器 - const myInterceptor = service.interceptors.request.use(onFulfilled, onRejected, options) - - // e.g. - // 创建请求拦截器 - const myInterceptor = service.interceptors.request.use( - config => { - // 可在此添加请求头信息 - return config - }, - err => { - // 在此处理错误 - }, - { - synchronous: false, - runWhen: (config) => { - // config参数继承自请求配置,即与创建实例配置一致 - return false - } - } - ) - - // 清除拦截器 - service.interceptors.request.eject(myInterceptor); - - // 清空请求拦截器 - service.interceptors.request.clear() - ``` - -- 错误处理 - - ```js - import { getData } from 'xxx' - - getData().then(res => { - - }).catch(e => { - console.log(e) - }) - ``` - -- 取消请求 - -> [官网的取消请求的例子](https://axios-http.com/zh/docs/cancellation),可以了解以下 - -## axios拦截器封装 - -> 简易拦截器封装 - -```js -import axios from 'axios'; -import { Message as ELMessage } from 'element-ui' - -const service = axios.create({ - baseURL: 'http://localhost:8081', // localhost替换成本地ip - timeout: 100000 -}) - - -service.interceptors.request.use(config => { - // 在此可以做请求头的处理,添加你所需要的请求头 - config.headers['userId'] = 'userId' - config.headers['userName'] = 'userName' - config.headers.Authorization = 'tk' - return config - }, - err => { - // 用饿了么弹窗提示 - ELMessage({ - showClose: true, - message: error && error.data.error.message, - type: 'error' - }); - return Promise.reject(error.data.error.message) - } -) - -service.interceptors.response.use( - res => { - const { data = {}, config = {}, headers = {} } = res || {} - const { code, message } = data - const { url, cancelMessage, responseType } = config - - // 对响应的code message做处理 - if (code && ![200, '200'].includes(code)) { - return Promise.reject() - } - - // 此外还可以对文件下载做处理 responseType - // blob arraybuffer stream等 - if (responseType === 'blob') {} - return data - }, - error => { - if(axios.isCancel(error)) { - return ELMessage.error(error.message) - } else { - const { response = {} } = error - const { status, data = {} } = response - let { message = '系统错误' } = data - - // 这里可以提示对应状态码的错误信息,也可以跳转到指定的页面,比方说404跳转到404的页面 - const statusMap = { - 400: '请求错误(400)', - 403: '拒绝访问(403)', - 500: '服务器错误(500)' - } - - // 对响应状态status进行判断,判断几种特殊的值 401 - 未授权 400 - 请求错误 403 - 拒绝访问 501 - 服务未实现等状态码 - if (statusMap.hasOwnProperty(status)) { - // 对于401后直接退出 - if(status === 401) { - // logout - } else { - let _message = message || statusMap[status] - ELMessage.error(_message) - } - - // 弹出提示信息框 - } else { - ELMessage.error(message) - } - - return Promise.reject(error) - } - } -) - -export default service - -``` - -## 接口防抖 - 即统一处理取消请求 - -> 一段时间内同样的接口(包含params和body参数及参数值)只能请求一次,如果重复相同的请求则取消后续的请求 -> 取消的请求还是会发出该请求,但浏览器不接受该响应了,实际并未真正意义上的取消 - -关于取消请求,有多种方式,axios从`v0.22.0`开始已经支持以fetch API方式 -- `AbortController` 取消请求,至于多种取消请求的方式,可以[参考官网的例子](https://axios-http.com/zh/docs/cancellation)自己进行拓展 - -这里我采用的方式是`new axios.CancelToken`的方式 - -```js -// 第一个版本 axios + lodash -import axios from 'axios' -import { isEqual } from 'lodash' - -class CancelToken { - constructor({ timeout = 500 } = {}) { - this.requestMap = [] // 请求列表 - this.timeout = timeout // 防抖时间,在timeout时间范围内的后续同样(url,method,data,params均一致)请求会被取消 - } - - // 每个请求添加唯一值,之后用作判断 - uniqueKey(config) { - // 解构,config为请求拦截的config配置,这里data和params给了默认值 - const { url, method, data = {}, params = {} } = config || {} - let uniqueKey = `${url}-${method}-${JSON.stringify(data)}-${JSON.stringify(params)}` - return uniqueKey - } - - // 添加处理 - append(config) { - const key = this.uniqueKey(config) - - // 寻找与当前请求一致的之前的请求,用key做比较 - const index = this.requestMap.findIndex(item => isEqual(item.key, key)) - - // 采用官网提供的 new axios.CancelToken 方式 - config.cancelToken = new axios.CancelToken(executor => { - if (index === -1) { - // 如果没有则直接添加 - this.requestMap.push({ - fun: executor, - key, - config, - time: new Date().getTime() - }) - } else { - // 如果有的话则查看是否在时间范围内 - if (new Date().getTime() - this.requestMap[index].time < this.timeout) { - // 直接取消,这里不需要再对data和params参数及参数值作比较,前面寻找索引的时候已经通过key对比 - // key里包含了data和params等 - executor('取消请求') - } else { - // 更新时间,方便下次进行时间比较,否则会一直进入该else判断 - this.requestMap[index].time = new Date().getTime() - } - } - }) - } -} - -export default CancelToken - - -// 第二种: -import axios from 'axios' -import { isEqual } from 'lodash' - -class CancelToken { - constructor({ timeout = 500 } = {}) { - this.pending = [] - this.timeout = timeout - } - - // 比较配置是否相等,返回布尔值 - isEqual(config1, config2) { - const urlEqual = config1.url === config2.url - const methodEqual = config1.method === config2.method - const dataEqual = isEqual(config1.data, config2.data) - const paramsEqual = isEqual(config1.params, config2.params) - return urlEqual && methodEqual && dataEqual && paramsEqual - } - - // 添加请求,不讲之前有无此请求,一律进行添加,判断交给remove方法 - append(config) { - config.cancelToken = new axios.CancelToken(executor => { - this.pending.push({ - fun: executor, - config, - time: new Date().getTime() - }) - }) - } - - // 去除请求 - remove(config) { - // 过滤掉不在时间范围内的, 就只剩下在时间范围内的了 - this.pending = this.pending.filter(item => item && new Date().getTime() - item.time < this.timeout) - - // 在时间范围内的进行循环,比较有无一致(url、method、data、params)的请求,如果有,则进行取消 - for (let i = 0; i < this.pending.length; i++) { - // 书写采用es6可选链运算符,如果不支持,可以选择安装插件,或者改为 && 判断也可 - if (this.isEqual(this.pending[i]?.config, config) && this.pending[i]?.config !== config) { - const index = this.pending.findIndex(i => i?.config === config) - this.pending[index]?.fun?.('取消请求') - this.pending[i] = null - } - } - } - - prevent(config) { - this.append(config) - this.remove(config) - } -} - -export default CancelToken - - - -// 使用 -- 在axios拦截器页面进行引入,将config传入 -import CancelToken from './cancelToken.js' - -const cancelToken = new CancelToken({}) // 可以传入配置对象,当前仅支持timeout配置,如果不提供配置对象,timeout默认500 - -// 创建axios实例 -const service = axios.create({ - baseURL: 'http://localhost:8081', // localhost替换成本地ip - timeout: 100000 -}) - -service.interceptors.request.use(config => { - // 第一种使用 - cancelToken.append(config) - - // 第二种使用 - cancelToken.prevent(config) - - return config -}) - - -``` -两种方法皆可实现取消请求的功能 - -axios取消请求,实际并未真正的取消,而是将浏览器中的接口状态 status,修改为canceled,响应还会发出,浏览器不对此接口做回应 - -如果项目中没有使用到lodash库的话,我觉得可以手写一个比较两个对象的方法,下面是手写比较方法 - -```js - -function isEqual(value, other) { - - function isObjectLike(value) { - return value != null && typeof value == 'object' - } - - if (value == null || other == null || (!isObjectLike(value) && !isObjectLike(other))) { - return value !== value && other !== other - } - - const toStr = Object.prototype.toString, - objTag = '[object Object]', - arrTag = '[object Array]' - - if(((toStr.call(value) !== objTag) && (toStr.call(other) !== objTag)) || (toStr.call(value) !== arrTag) && (toStr.call(other) !== arrTag)) { - return value === other || JSON.stringify(value) === JSON.stringify(other) - } - - let valueKeys = Object.keys(value), - otherKeys = Object.keys(other) - - if(valueKeys.length !== otherKeys.length) { - return false - } - - for (let i = 0; i < valueKeys.length; i ++) { - let key = valueKeys[i] - let item1 = value[key], - item2 = other[key] - - if(((toStr.call(item1) === objTag) && (toStr.call(item2) === objTag)) || (toStr.call(item1) === arrTag) && (toStr.call(item2) === arrTag)) { - // 值是对象或数组则再次进行比较 - return isEqual(item1, item2) - } else if(item1 === item2) { - return true - } else { - return false - } - } -} - -let obj1 = { 'b': { 'c': { 'd': 333 } } } -let obj2 = { 'b': { 'c': { 'd': 222 } } } - -console.log(isEqual(obj1, obj2)); // false - -let arr1 = [1,2,{'a': 12, 'b': [1,2,3]}] -let arr2 = [1,2,{'a': 12, 'b': [1,2,3]}] - -console.log(isEqual(arr1, arr2)); // true - -``` - -#### 有什么不足,需要改进的地方请在评论区中指出,后继会完善,感谢!文章已同步至[github.io](https://labixiong.github.io/)感兴趣的可以前往查看。 - -## 参考 -- [菜鸟ajax教程](https://www.runoob.com/ajax/ajax-intro.html) -- [axios官网](https://axios-http.com/zh/) diff --git "a/_posts/2024-03-25-qiankunjs\345\276\256\345\211\215\347\253\257\346\241\206\346\236\266\350\257\246\350\247\243.md" "b/_posts/2024-03-25-qiankunjs\345\276\256\345\211\215\347\253\257\346\241\206\346\236\266\350\257\246\350\247\243.md" deleted file mode 100644 index d188370..0000000 --- "a/_posts/2024-03-25-qiankunjs\345\276\256\345\211\215\347\253\257\346\241\206\346\236\266\350\257\246\350\247\243.md" +++ /dev/null @@ -1,734 +0,0 @@ ---- -layout: post -title: qiankunjs微前端框架详解 -subtitle: qiankunjs微前端框架并实践,搭建过程中出现什么样的问题 -date: 2024-03-25 -author: LBX -header-img: img/bg-little-universe.jpg -catalog: true -tags: - - 前端 - - qiankunjs - - vue2 - - vue3 - - wepack - - vite ---- - -> qiankun 是一个基于single-spa的微前端实现库,旨在帮助大家能更简单的构建一个生产可用微前端架构系统。 - -# 简介 - -qiankun 是一个基于 [single-spa](https://github.com/CanopyTax/single-spa) 的[微前端](https://micro-frontends.org/)实现库,旨在帮助大家能更简单的构建一个生产可用微前端架构系统。 - -qiankun 孵化自蚂蚁金融科技基于微前端架构的云产品统一接入平台。 - -## qiankun的核心设计概念 - - -- 简单 - - 由于主应用微应用都能做到技术栈无关,qiankun 对于用户而言只是一个类似 jQuery 的库,你需要调用几个 qiankun 的 API 即可完成应用的微前端改造。同时由于 qiankun 的 HTML entry 及沙箱的设计,使得微应用的接入像使用 iframe 一样简单。 - -- 解耦/技术栈无关 - - 微前端的核心目标是将巨石应用拆解成若干可以自治的松耦合微应用,而 qiankun 的诸多设计均是秉持这一原则,如 HTML entry、沙箱、应用间通信等。这样才能确保微应用真正具备 独立开发、独立运行 的能力。 - -## 为什么不是iframe? - -如果不考虑体验问题,iframe是微前端的最优解 - -iframe 最大的特性就是提供了浏览器原生的硬隔离方案,不论是样式隔离、js 隔离这类问题统统都能被完美解决。但他的最大问题也在于他的隔离性无法被突破,导致应用间上下文无法被共享,随之带来的开发体验、产品体验的问题。 - -## qiankun特性 - -- **基于 [single-spa](https://github.com/CanopyTax/single-spa)** 封装,提供了更加开箱即用的 API。 --  **技术栈无关**,任意技术栈的应用均可 使用/接入,不论是 React/Vue/Angular/JQuery 还是其他等框架。 -- **HTML Entry 接入方式**,让你接入微应用像使用 iframe 一样简单。 -- **样式隔离**,确保微应用之间样式互相不干扰。 -- **JS 沙箱**,确保微应用之间 全局变量/事件 不冲突。 -- **资源预加载**,在浏览器空闲时间预加载未打开的微应用资源,加速微应用打开速度。 -- **umi 插件**,提供了 [@umijs/plugin-qiankun](https://github.com/umijs/plugins/tree/master/packages/plugin-qiankun) 供 umi 应用一键切换成微前端架构系统。 - -## 什么是微前端? - -微前端是一种多个团队通过独立发布功能的方式来共同构建现代化 web 应用的技术手段及方法策略。 - -微前端架构旨在解决单体应用在一个相对长的时间跨度下,由于参与的人员、团队的增多、变迁,从一个普通应用演变成一个巨石应用后,随之而来的应用不可维护的问题。这类问题在企业级 Web 应用中尤其常见。 - -## 微前端的核心价值 - -1. 技术栈无关 - 主框架不限制接入应用的技术栈,微应用具备完全自主权 -2. 独立开发、独立部署 - 微应用仓库独立,前后端可独立开发,部署完成后主框架自动完成同步更新 -3. 增量升级 - 在面对各种复杂场景时,我们通常很难对一个已经存在的系统做全量的技术栈升级或重构,而微前端是一种非常好的实施渐进式重构的手段和策略 -4. 独立运行时 - 每个微应用之间状态隔离,运行时状态不共享 - - -# 如何快速上手 - -## 安装qiankun - -```shell -yarn add qiankun # 或者npm i qiankun -S -``` - -## 在主应用注册子应用 - -```javascript -// 需要在主应用入口函数中进行注册 -import { registerMicroApps, start } from 'qiankun'; - - -registerMicroApps([ - { - name: 'react app', // app name registered - entry: '//localhost:7100', - container: '#yourContainer', - activeRule: '/yourActiveRule', - }, - { - name: 'vue app', - entry: { scripts: ['//localhost:7100/main.js'] }, - container: '#yourContainer2', - activeRule: '/yourActiveRule2', - }, -], { - beforeLoad: app => {}, - beforeMount: app => { - // 子应用挂载前操作,可以将当前的子应用的配置保存起来 - }, - afterUnmount: app => { - // 子应用卸载后清除当前子应用的配置等等 - }, -}); - - -start(); - - -// 子应用入口文件代码 -export function bootstrap() {} - -export function mount() {} - -export function unmount() {} -``` - -- **name:** 微应用名字 需确保唯一性 -- **entry:** 微应用入口路径 -- **activeRule:** 注册微应用时,微应用的路由匹配规则 - -注册成功后,当浏览器的url发生变化时,会自动触发qiankun的匹配逻辑,所有 activeRule 规则匹配上的微应用就会被插入到指定的 container 中,同时依次调用微应用暴露出的生命周期钩子。 - -如果微应用不是直接跟路由关联的时候,你也可以选择手动加载微应用的方式: - -```javascript -// 主应用 -import { loadMicroApp } from 'qiankun'; - -loadMicroApp({ - name: 'app', - entry: '//localhost:7100', - container: '#yourContainer', - props: {} -}, { - sandbox: true, - // ... -}); - - -// 子应用入口文件中除了要导出bootstrap、mount、unmount还需要额外导出一个update生命周期函数 - -// ... -export async function update(props) { - // ... - render(props) -} - -``` - -name、entry、container三个属性为必填项,props为可选属性,在初始化时主应用需要传递给微应用的数据。 - -### **自动加载和手动加载的区别:** - -1. 自动加载的方式增加了 `activeRule` 配置,此属性是必选的,为微应用的激活规则 -2. 自动加载的第二个参数是全局的微应用生命周期钩子;手动加载的第二个参数是一些配置,包括sandbox(是否开启沙箱,默认为开启)、singular(是否为单实例场景,指同一时间只会渲染一个微应用,默认为false)等属性 -3. 手动加载微应用会返回微应用的实例,包括但不限于微应用的生命周期钩子,可以保存起来供主应用在合适的位置进行调用 - -[loadMicroApp API](https://qiankun.umijs.org/zh/api#loadmicroappapp-configuration) - -### 手动加载微应用的运用场景 - -如果微应用是一个不带路由的可独立运行的业务组件,可以使用手动加载这个应用 - - -## 接入微应用 - -微应用无需安装qiankun,即可使用,但需要微应用在项目入口文件中暴露指定生命周期函数 - -### 导出相应的生命周期钩子 - -```javascript -// 只会在微应用初始化的时候调用一次,下次再进入会直接跳过该函数触发mount函数 -// 通常做一些初始化操作,对微应用进行预设,还有不会在unmount阶段被销毁的应用级别的缓存等等 -export async function bootstrap(props) {} - -// 每次进入都会调用mount方法,通常在这里触发渲染方法,开始渲染页面 -export async function mount(props) { - render(props) -} - -// 在此处卸载微应用的实例、清空路由、清空html等操作 -export async function unmount() {} - -// 可选生命周期钩子,仅使用loadMicroApp方式手动加载微应用时生效 -export async function update(props) {} -``` - - -### 打包配置 - -以webpack为例 - -```javascript -const packageName = require('./package.json').name; - - -module.exports = { - output: { - library: `${packageName}-[name]`, - libraryTarget: 'umd', - - // chunkLoadingGlobal为webpack v5的配置 - // 如使用的是webpack v4版本,需要将此配置改为jsonpFunction,属性值与webpack v5版本一致 - // webpack v4 -- jsonpFunction: `webpackJsonp_${packageName}` - chunkLoadingGlobal: `webpackJsonp_${packageName}`, - }, -}; -``` - -**library** - ```${pkgson.name}-[name]```,这里的`pkgson.name`值是`vue2Template`会将你的library bundle暴露为名为`vue2Template-name`的全局变量,使用者会通过此名称来import。 - -**libraryTarget** - 'umd',通常与`library`选项配合使用,最简单的解释就是以umd的方式对library进行暴露,方便在AMD或者CommonJS require之后使用。 - -**jsonpFunction** - `webpackJsonp_${pkgson.name}`,用于异步加载模块或连接多个初始化模块,如果使用了`output.library`这个配置,这个library name会自动拼接`output.jsonpFunction`的值,所以这里需要手动指定。 - -**chunkLoadingGlobal** - 用于`webpack`加载`chunks` - -### 新增 `public-path` 文件 - -项目中新增 `public-path` 文件,用于修改运行时的 `publicPath` - -```javascript -// 例如增加到src目录下,src/public-path.js文件内容 -if (window.__POWERED_BY_QIANKUN__) { - __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__ -} - -// 在入口文件中引入 -import './public-path' -// ... -``` - -### 微应用设置路由 - -路由模式建议使用 `history` 模式的路由,路由的 `base` 值和它的 `activeRule` 值保持一致 - -### 配置允许跨域 - -同样是以webpack为例: - -```javascript -// webpack.config.js -module.exports = { - // ... - devServer: { - // ... - headers: { - 'Access-Control-Allow-Origin': '*' - } - } -} -``` - - -# 常见问题 - -[qiankun官网整理的常见问题](https://qiankun.umijs.org/zh/faq) - -## 主应用和子应用之间如何进行通信 - -https://blog.csdn.net/weixin_43972437/article/details/128154083 - -https://www.cnblogs.com/goloving/p/15599561.html - -1. `localStorage`、`sessionStorage` - - 主应用通过 `localStorage` 设置全局主题和中英文模式,以便微应用中使用 - -2. `Actions` - `qiankun`内部提供了 `initGlobalState` 方法用于注册 `MicroAppStateActions` 实例用于通信,该实例有三个方法: - - `setGlobalState`: 全局状态设置新的值时,通知所有观察者函数 - - `onGlobalStateChange`: 注册观察者函数,当全局状态发生变化时触发观察者函数 - - `offGlobalStateChange`: 移除当前应用的状态监听,微应用 umount 时会默认调用 - ```javascript - // 主应用 - import { initGlobalState, MicroAppStateActions } from 'qiankun'; - - // 初始化 state - const actions: MicroAppStateActions = initGlobalState(state); - - actions.onGlobalStateChange((state, prev) => { - // state: 变更后的状态; prev 变更前的状态 - console.log(state, prev); - }); - actions.setGlobalState(state); - actions.offGlobalStateChange(); - - // 微应用 - // 在生命周期mount中获取通信方法,使用方式和主应用一致 - export function mount(props) { - props.onGlobalStateChange((state, prev) => { - // state: 变更后的状态; prev 变更前的状态 - console.log(state, prev); - }) - } - ``` - - 此方式使用简单,官方支持性高,适合通信较少的业务场景,例如:主应用进行布局样式切换、中英文切换、主题切换、切换用户所属单位、组织等,微应用根据当前的全局状态进行更改 - - 缺点就是微应用单独运行时需要额外配置没有 `Actions` 的逻辑,通信场景较多时,容易出现状态混乱、维护困难等问题 -4. `Shared` - - 主应用通过 `vuex` `redux` `mobx`等任一状态管理工具正常维护一个状态,然后创建一个 `Shared`实例,遵循开闭原则,通过 `props` 将 `Shared` 实例传递给微应用。 - - 同样的微应用也需要维护一个 `Shared`, 当在主应用下运行时,就对当前维护的 `Shared` 进行重载,如果单独运行时就会使用自身的 `Shared` - - 微应用可以自由选择状态管理库,无需了解主应用的状态池细节,同时也将具备独立运行的能力。 - - 缺点也就是主应用和微应用都需要维护 `Shared`,增加了维护成本和项目复杂度 - - 适用于主应用和微应用间频繁交互的场景中 -5. `props` - - 主应用在注册微应用时通过 `props` 属性传递给微应用所需要的属性 - -## 主应用和子应用公共组件、公共样式,这些如何进行维护? - -**公共组件:** - -官网解释:共享依赖本身并不建议,即便所有的团队都是用一个框架,但如果真的有这种需求,可以在微应用中将公共依赖配置成 `external` ,然后在主应用中导入这些依赖 - -至于为何不建议共享依赖? - -官网说qiankun 2.0 版本将提供一种更智能的方式使其自动化。但我看了qiankun github仓库,这个[issues](https://github.com/umijs/qiankun/issues/627)依然处于open状态 - -大致给出个人觉得可行性的方案: - -1. 常用的工具库封装成 `npm` 包,团队管理升降级 - - 缺点: - - - 每个微应用都会打包该模块,导致依赖的包冗余,没有真正意义上的复用 - - 当包进行更新发布了,微应用还需要重新构建,调试麻烦低效,虽然可以用npm link来解决 - -2. 使用 `Git Submodule` 管理子模块源码 - - 同样是依赖npm,与npm不同的是,npm管理的是模块构建产物,git submodule管理的是模块源码,如果不想模块代码暴露出去,可以使用此方式 - -3. `Monorepo` - - 单体式仓库,将多个项目放到同一个仓库里面进行管理,统一管理各个模块的构建流程、版本号等。可以避免大量的 `node_modules` 冗余 - - 缺点就是统一构建工具所带来的更高的要求以及仓库体积过大,维护成本高的问题 - -4. `Webpack Externals` - - `externals`中文意思就是外部的,通过在 `externals` 配置项中定义的模块不会存在最终输出的 `bundle` 中 - - 移除掉的模块可以通过 `CDN` 的方式在入口文件中引入,也可以自己预先打包好,再进行引入 - - 缺点就是微应用技术栈多样化的情况,`externals` 并无法支持多版本的情况 -5. `Webpack DLL` - - 在一个独立的 `webpack` 进行设置 `webpack.dll.config.js`,目的是为了创建一个把所有的第三方库依赖打包到一起的 `bundle` 的 `dll` 文件里面,同时还会生成一个 `manifest.json` 的文件,用于让使用该第三方依赖集合的应用配置的 `DllReferencePlugin` 能映射到相关的依赖上去 - -6. 联邦模块 `Module Federation` - - `webpack v5` 新出的一个功能,真正意义上实现跨应用间的模块共享 - -7. 主应用使用 `props` 传递 - - 主应用通过 `props` 属性传递给子应用,子应用可在入口文件导出的 `bootstrap` 生命周期函数中接收 - - 缺点:如果微应用单独运行的话,还需要安装一遍 - -**公共样式:** - -提取主应用和微应用在主应用的入口文件中引入,子应用可以直接使用 - -``` -// 主应用中定义样式 使用scss定义 并在入口文件中导入 -.mr-5 { - margin-right: 5px; -} - -// 微应用页面中使用 同样是使用scss -// f12检查页面元素 会正常解析单位也是 px - - -// 微应用页面中使用 使用less -// 会解析为相对单位 1.25rem -``` - -使用 `scss` 的微应用会正常解析定义的单位,单位同样是 `px` - -使用 `less` 的微应用也会正常解析,不过会解析为相对单位 `rem`, 例如 `margin-right: 1.25rem` - - -## 同样的外部资源主应用加载完成之后,子应用如果也需要加载相同的资源是重新加载?还是用主应用已经加载好的? - -可以将一些通用性的库放到主应用加载,第三方库加载后都会抛出一个默认全局对象,比如 `lodash`、`jquery` 这些仓库都会抛出,可以判断 `window` 中是否有这些对象,如果有说明主应用已经加载好;如果没有则重新加载 - -## 主应用和子应用可以部署在不同的服务器吗? - -可以,使用`Nginx`代理进行访问。将主应用服务器上一个特殊路径的请求全部转发到微应用的服务器上。 - -主应用所在服务器上所有指定开头(例如: /app1)的请求都转发的微应用服务器上 - -主应用 `Nginx` 配置如下: -```shell -^/app1/ { - proxy_pass http://www.microapp.com/app1/; - proxy_set_header Host $host:$server_port; -} - -^/api/ { - proxy_pass http://www.microapp.com/api/; - proxy_set_header Host $host:$server_port; -} -``` - -注册微应用时,`entry` 可以为相对路径,`activeRule` 不可以和 `entry` 一样,否则主应用页面刷新就会变成微应用 - -```javascript -registerMicroApps([ - { - name: 'app1', - entry: '/app1/', - container: '#subapp-container', - activeRule: '/child/app1' - } -]) -``` - -`activeRule`需要跟子应用路由的 `base` 一致 - -## history模式路由刷新404问题如何解决? - -举个浏览器解析SPA应用的例子: - -SPA应用在输入页面路由时,发送network会发送document请求,返回html文件,浏览器进行解析html文件并加载其中的js和css文件,执行js让`History API`接管页面,重定向到指定路由(例如:http://localhost:8080/login),接着渲染`login`路由所对应页面 - -当我们再次对页面进行刷新时,服务器同样会尝试根据刷新的URL返回对应的页面,但是服务器上并没有login路由相应的文件。 - -router(不管是vue-router还是react-router)只是前端来用,并不是给服务器用的 - -如何防止? - -**本地开发:** - -```js -// webpack.config.js -module.exports = { - // ... - devServer: { - historyApiFallback: true - } -} - -// webpack.config.js -module.exports = { - // ... - devServer: { - historyApiFallback: { - rewrites: [ - // to中配置需要根据所配置的publicPath进行配置 - // publicPath配置默认为 / - // 如果配置为 '/views' 则 to 需要配置为 '/views/index.html' - // 属性值与HtmlWebpackPlugin所配置的filename属性一致 - { from: /\//, to: '/index.html' } - ], - disableDotRule: true // 当在路径中使用点时(在Angular中经常遇到),需要设置此属性为true - } - } -} -``` - -[connect-history-api-fallback文档地址获取更多historyApiFallback配置信息](https://github.com/bripkens/connect-history-api-fallback) - -`historyApiFallback (boolean = false object)` : webpack中devServer的配置项,当用到html5中的`History API`的时候,为了确保页面不会相应404的情况,需要设置此属性为true - -**Nginx如何调整** - -```shell -# 使用root时,实际获取到的静态资源路径是 data/app/index.html -location /app/ { - root data; - index index.html index.htm; - try_files $uri $uri/ /default.html @default; -} - - -# 使用alias时,实际获取到的静态资源的路径是 data/index.html -location /app/ { - alias data/; - index index.html index.htm; - try_files $uri $uri/ /default.html @default; -} -``` - -- $uri/,尾部带斜杠,此时表示为一个目录,此时会在目录下查找由index指定的值 -- 如果没有找到任何文件,则会对最后一个参数指定的uri进行内部重定向 -- attention:最后一个参数是回退URI且必须存在(命名location也可以当做最后一个参数使用),否则会出现内部500错误 - - -**extend:** - -**root和alias区别:** - -1. root指定路径尾部斜杠可加可不加,alias尾部斜杠是必须要加的 -2. root属性值最终会拼接到路径中,alias属性值不会拼接到路径中,会直接在alias属性的值下面去找资源 -3. root最终获取的静态页面路径为: 域名 + root属性值 + 匹配规则 + index属性值;alias最终获取的静态页面路径为: 域名 + alias属性值 + index属性值 -4. alias是目录别名,root是最上层目录 - - -## 微应用出现接口404问题 - -以axios为例,baseUrl要设置为绝对路径 - -例如:`http://localhost:8080/dev-api` 而不是 `/dev-api` - -## qiankun下请求子应用静态资源不正常展示,例如图片等资源 - -**vue3 + vite项目** - -解决方式:在`vite.config.ts`文件中的导出的配置中`server`对象增加origin配置 - -```js -export default defineConfig(({ mode }: ConfigEnv): UserConfig => { - return { - server: { - origin: `http://localhost:${Number(env.VITE_APP_PORT)}`, - // ... - } - } -}) -``` - -**vue2项目** - -要确保 `publicPath` 配置正确 - -确保运行时的 `publicPath` 配置,之前提到的新建 `public-path` 文件,并确保在入口文件中引入,内容为: - -```js -if (window.__POWERED_BY_QIANKUN__) { - __webpack_public_path__ = window.__INJECTED_PUBLIC_PATH_BY_QIANKUN__ -} -``` - -## 微应用打包之后css中的字体文件和图片加载404 - -`qiankun`将外链样式改成了内联样式,但是字体文件和背景图片的加载路径是相对路径 - -`css`文件一旦打包完成,就无法通过动态修改 `publicPath` 来修正其中的字体文件和背景图片的路径 - -- 将所有图片等静态资源上传至 `cdn`, `css` 中直接引用地址 -- 借助 `webpack` 的 `url-loader` 将字体文件和图片打包成 `base64` (适用于字体文件和图片体积小的项目) - - ```javascript - // 以vue2项目为例 - // vue.config.js - - module.exports = { - // ... - chainWebpack: config => { - config.module - .rule('images') - .use('url-loader') - .tap(options => - merge(options, { - limit: 5 * 1024 - }) - ) - config.module - .rule('fonts') - .test(/\.(png|jpe?g|gif|webp|woff2?|eot|ttf|otf)$/i) - .use('url-loader') - .loader('url-loader') - .tap(options => { - options = { - // limit: 10000, - name: '/static/fonts/[name].[ext]' - } - return options - }) - .end() - } - } - ``` -- 对于字体和图片比较大的可以使用 `webpack` 的 `file-loader`在打包时给其注入完整路径 - ```javascript - const publicPath = process.env.NODE_ENV === 'production' ? 'https://qiankun.umijs.org/' : `http://localhost:${port}`; - module.exports = { - module: { - rules: [ - { - test: /.(png|jpe?g|gif|webp)$/i, - use: [ - { - loader: 'file-loader', - options: { - name: 'img/[name].[hash:8].[ext]', - publicPath, - }, - }, - ], - }, - { - test: /.(woff2?|eot|ttf|otf)$/i, - use: [ - { - loader: 'file-loader', - options: { - name: 'fonts/[name].[hash:8].[ext]', - publicPath, - }, - }, - ], - }, - ], - }, - }; - ``` -- 将前两种方案结合起来,小文件转 `base64`,大文件注入路径前缀 - -## 主应用如何配置404页面? - -将404页面配置为一个路由,在主应用的路由钩子函数判断,如果既不是主应用路由也不是微应用路由,就跳转到404页面 - -``` -const childrenPath = ['/app1', '/app2']; -router.beforeEach((to, from, next) => { - if (to.name) { - // 有 name 属性,说明是主应用的路由 - return next(); - } - if (childrenPath.some((item) => to.path.includes(item))) { - return next(); - } - next({ name: '404' }); -}); -``` - -## 微应用使用 `router.replace` `router.push` 无法正常跳转 - -有时候需要从当前微应用跳转到另一个微应用中,或者跳转某个页面时会使整个页面重新刷新,状态丢失等 - -如果都是 `history` 模式路由可使用 `window.history.pushState` 或者 `window.history.replaceState` 方式进行跳转 - -如果主应用 `hash`模式,子项目使用 `history` 模式,则依然可以借助`window.history.pushState` 或者 `window.history.replaceState` 方式进行跳转 - -如果都是 `hash` 模式,可以使用 `window.location.hash` 进行跳转 - -## 微应用切换到主应用的时候,出现主应用未加载css的问题 - -先复制一下 HTMLHeadElement.prototype.appendChild 和 window.addEventListener ,路由钩子函数 beforeEach 中判断一下,如果当前路由是子项目,并且去的路由是父项目的,则还原这两个对象。 - -## 主应用下切换微应用出现菜单不显示的情况 - -微应用入口文件中导出生命周期,将单独渲染的情况分离出来到 `render.js`文件中,在入口文件 `mount` 生命周期中接受 `props` 并使用 `render` 函数渲染微应用 - -```javascript -// main.js - -import { render } from './render' - -export async function mount(props) { - render(props) -} - -// render.js -import './permission' -export const render = (props) => { - // ... -} - -``` - -首次加载微应用时会执行 `permission` 文件的内容,当切换到另一个微应用再切换到当前应用时,却不会进入 `permission` 文件,只会走 `render` 函数里面的逻辑,如果 `redner` 函数中没有加载路由的代码则菜单就不会显示 - -# 深思熟虑 - -## 为什么libraryTarget要设置为umd? - -这是为了在 `qiankun` 架构下让主应用在执行微应用的js资源时可以通过 `eval`,将 `window` 绑定到一个 `Proxy` 对象上,防止污染全局变量,方便对脚本的window相关操作做劫持处理,达到子应用的脚本隔离 - -`umd - Universal Module Definition`, 通用模块定义规范,兼容性更高,模块定义的跨平台解决方案,通俗的理解就是可以让代码在 `nodejs` 和浏览器环境中都可以运行 - -## 什么是运行时的 `publicPath` ? - - [webpack output.publicPath](https://webpack.docschina.org/guides/public-path/#on-the-fly) - - -## `npm link`起到什么作用? - -开发npm模块的时候,我们会希望边开发边试用,比如本地调试的时候,引入的模块会自动加载本机开发中相应的模块。 `Node` 规定,使用一个模块时,需要将其安装到全局的或项目的 `node_modules` 目录之中。对于开发中的模块,解决方式就是在全局的 `node_modules` 目录之中,生成一个符号链接,指向模块的本地目录 - -`npm link` 就是起到这个作用,会自动简历符号链接 - -例如,自己开发了一个模块 `myModule` ,目录为 `src/myModule`,你自己的项目 `myProject` 要用到这个模块,项目目录为 `src/myProject` 。首先,在模块目录 `src/myModule` 下运行 `npm link` 命令。 - -``` -src\myModule> npm link -``` - -上面的命令会在npm全局模块目录内,生成一个符号链接文件,该文件的名字就是 `package.json`文件中指定的模块名。 - -这个时候,已经可以全局调用 `myModule` 模块了。但是,如果我们要让这个模块安装在项目内,还需要切换到项目目录,再次运行 `npm link` 命令,并指定模块名 - -``` -src\myProject> npm link myModule -``` - -上面命令等同于生成了本地模块的符号链接,项目里的 `node_modules/myModule` 就链接到了全局npm模块目录的 `myModule` 模块 - -`myModule`的任何变化,都可以直接反应在 `myProject`项目之中,**缺点**就是,任何在 `myProject`目录中对 `myModule` 的修改,都会反应到模块的源码中。 - -如果不再需要该模块,可以在项目目录内使用`npm unlink [package name]` 命令,进行删除符号链接。 - - -# 结语 - -官方文档只是给出了一个大概雏形,具体的配置还需要自己进行更多的项目实战,在项目中进行总结 - -博客内容同步更新至 `https://labixiong.github.io/` 网站 - - -# 参考文档 - -- [可能是你见过的最完善的微前端解决方案](https://zhuanlan.zhihu.com/p/78362028) -- [微前端的核心价值](https://zhuanlan.zhihu.com/p/95085796) -- [为什么不是iframe](https://www.yuque.com/kuitos/gky7yw/gesexv) -- [publicPath](https://webpack.docschina.org/guides/public-path/#on-the-fly) -- [micro-frontends](https://micro-frontends.org/) -- [npm link 阮一峰](https://javascript.ruanyifeng.com/nodejs/npm.html#toc18) -- [qiankun中文官网](https://qiankun.umijs.org/zh) -- [微前端模块共享你真的懂了吗](https://juejin.cn/post/6984682096291741704) -- [如何复用公共依赖 目前issues处于open状态](https://github.com/umijs/qiankun/issues/627) -- [webpack官网 Module Federation](https://webpack.js.org/concepts/module-federation/#root) -- [不同的历史模式](https://router.vuejs.org/zh/guide/essentials/history-mode.html) - diff --git "a/_posts/2025-02-08-\345\215\227\346\226\271\345\214\273\347\247\221\345\244\247\345\255\246\347\256\200\344\273\213.md" "b/_posts/2025-02-08-\345\215\227\346\226\271\345\214\273\347\247\221\345\244\247\345\255\246\347\256\200\344\273\213.md" new file mode 100644 index 0000000..b512d9e --- /dev/null +++ "b/_posts/2025-02-08-\345\215\227\346\226\271\345\214\273\347\247\221\345\244\247\345\255\246\347\256\200\344\273\213.md" @@ -0,0 +1,76 @@ +南方医科大学(Southern Medical University)是一所位于广东省广州市的重点大学,以下是关于该校的详细介绍: + +### 一、基本信息 + +* **创办时间**:1951年10月30日,前身为中国人民解放军第一军医大学。 +* **办学性质**:公办大学 +* **学校类别**:医药类 +* **学校特色**: + + 全国重点大学(1979年入选) + + 广东省高水平大学重点建设高校(2016年入选) + + “部委省”共建医科高校(2016年) + + 卓越医生(中医)教育培养计划(2015年入选) + + 基础学科拔尖学生培养计划2.0基地(2021年入选) +* **主管部门**:广东省教育厅 +* **现任领导**:张玉润(党委书记)、黎孟枫(校长) +* **校训**:博学笃行,尚德济世 +* **校歌**:《爱在南方》 +* **校庆日**:10月30日 +* **地址**: + + 校本部:广东省广州市白云区沙太南路1023号-1063号 + + 顺德校区:广东省佛山市顺德区容桂街马岗大道33号 +* **学校官网**:[http://www.smu.edu.cn/](http://www.smu.edu.cn/) + +### 二、办学规模 + +* **占地面积**:两个校区总占地面积为168万平方米(或说1530亩为顺德校区面积),建筑面积114.6万平方米。 +* **院系设置**:截至2024年4月,学校设有22个院系,开设29个本科专业。 +* **师资力量**: + + 现有专业技术人员6079人,其中高级专业技术职称1100人。 + + 拥有院士4人(含双聘院士)、国家级教学团队、国家教学名师、长江学者等高层次人才。 + + 博士生导师236名、硕士生导师639名。 +* **学生人数**:截至2024年4月,有本科生3062名(该数据可能随时间有所变动)。 + +### 三、学科建设 + +* **重点学科**: + + 拥有5个国家重点及培育学科、6个国家中医药管理局重点学科、10个广东省重点学科、1个广州市重点学科。 + + 14个学科入围ESI全球前1%,其中临床医学和药理学与毒理学入围全球前0.5‰,ESI总体排名位居全国第46。 +* **学位授权点**: + + 11个博士学位授权一级学科,16个硕士学位授权一级学科。 + + 4个博士专业学位授权类别,15个硕士专业学位授权类别。 + + 10个博士后科研流动站。 + +### 四、教学建设 + +* **教学成果**: + + 先后作为第一完成单位获国家级教学成果奖12项、省级教学成果奖49项,其中国家级教学成果一等奖2项。 + + 现有国家特色专业7个、广东省特色专业16个、广东省名牌专业6个。 + + 获批国家级一流本科专业建设点23个、国家级一流本科课程40门,入选数量均位居全国医药院校第1。 +* **教学设施**: + + 现有国家级规划教材17部、国家级精品课程8门、国家级课程思政示范课程(教学名师和团队)2项、国家级实验教学示范中心4个。 + + 获首届全国优秀教材建设奖2项、首批国家临床教学培训示范中心1个。 + +### 五、科学研究 + +* **科研平台**: + + 现有国家重点实验室、国家临床医学研究中心、粤港澳大湾区脑与类脑研究中心等国家和省部级科研平台132个。 + + 科技部重点领域创新团队2个、教育部创新团队2个、国家自然科学基金创新研究群体1个。 +* **科研成果**: + + 共获国家科技三大奖30项,省部级一等奖62项,获国家科技奖数量位居广东省属高校第一。 + + 2024年,学校获国家自然科学基金429项,立项数位居全国高校第16位、全国独立医科大学首位、广东省高校第2位,连续9年跻身全国30强。 + + 2024年获中国博士后科学基金93项,位列全国高校第13、独立医科院校第1。 + + 学校先后在Nature、Cell、NEJM、JAMA、Lancet等国际著名期刊发表高水平论文。 + +### 六、医疗实力 + +* **附属医院**:现有直属附属医院8家,合作共建医院8家,其中三级甲等医院12所,展开床位数超过23000张,年诊疗服务人次约2600万人次。 +* **临床重点专科**:拥有国家级临床重点专科(含中医)47个、广东省临床重点专科(含中医)82个(不含十二五期间数量)、广东省医疗质量控制中心23个。 + +### 七、社会评价 + +* 校园环境优美,绿化良好,交通便利。 +* 师资力量雄厚,教学水平高,科研实力强。 +* 学校设施新全,为学生提供了良好的学习和生活环境。 + +综上所述,南方医科大学是一所历史悠久、办学实力雄厚的医药类高校,在学科建设、教学建设、科学研究以及医疗实力等方面均取得了显著成就。 \ No newline at end of file diff --git "a/_posts/2025-02-08-\346\211\213\346\234\257\347\247\221\345\256\244\345\222\214\351\235\236\346\211\213\346\234\257\347\247\221\345\256\244.md" "b/_posts/2025-02-08-\346\211\213\346\234\257\347\247\221\345\256\244\345\222\214\351\235\236\346\211\213\346\234\257\347\247\221\345\256\244.md" new file mode 100644 index 0000000..18f33cd --- /dev/null +++ "b/_posts/2025-02-08-\346\211\213\346\234\257\347\247\221\345\256\244\345\222\214\351\235\236\346\211\213\346\234\257\347\247\221\345\256\244.md" @@ -0,0 +1,25 @@ +手术科室和非手术科室是医院临床科室的两大主要分类,它们在治疗手段、疾病类型、患者群体以及科室配置上存在着显著的差异。 + +**作者:** 文心一言 + +### 一、治疗手段 + +* **手术科室**:以手术治疗为主要手段,通过手术刀、手术器械等对患者进行诊断和治疗。手术科室通常包括普外科、心胸外科、肝胆外科、泌尿外科、神经外科、整形外科和烧伤外科等多个专科科室。这些科室的患者通常需要经过手术评估,并在必要时进行手术治疗。 +* **非手术科室**:以药物治疗、物理治疗、心理治疗等非手术治疗手段为主,通常称为内科系统。非手术科室包括心血管科、呼吸科、消化科、肾脏内科、血液科、内分泌科、神经内科、老年医学科等学科。这些科室的患者通常通过药物治疗、营养支持、心理干预等方式进行治疗。 + +### 二、疾病类型 + +* **手术科室**:主要处理需要手术治疗的疾病,如肿瘤切除、器官移植、骨折修复等。这些疾病通常涉及到器官、组织的切除、重建或修复。 +* **非手术科室**:主要处理内科疾病,如高血压、糖尿病、呼吸系统疾病、消化系统疾病等。这些疾病通常通过药物治疗、生活方式调整等方式进行治疗,不涉及手术治疗。 + +### 三、患者群体 + +* **手术科室**:患者群体通常是需要进行手术治疗的患者,包括因外伤、肿瘤、感染等原因需要手术的患者。 +* **非手术科室**:患者群体主要是内科疾病患者,包括慢性疾病患者、急性病患者等。这些患者通常不需要手术治疗,而是需要药物治疗、营养支持等内科治疗手段。 + +### 四、科室配置 + +* **手术科室**:通常配备有手术室、麻醉科、重症监护室等配套设施,以确保手术过程的安全和有效性。手术室通常配备有各种先进的手术器械和设备,以满足不同手术的需求。 +* **非手术科室**:主要配备有病房、治疗室、检查室等设施,以提供药物治疗、物理治疗等非手术治疗手段。同时,非手术科室还可能需要配备有心电图机、B超机等检查设备,以辅助诊断和治疗。 + +综上所述,手术科室和非手术科室在治疗手段、疾病类型、患者群体以及科室配置上存在着显著的差异。患者在选择科室时,应根据自己的病情和医生的建议进行选择。 \ No newline at end of file diff --git "a/_posts/2025-02-17-\346\237\257\345\260\224\350\216\253\345\223\245\346\264\233\345\244\253\346\234\200\345\220\216\347\232\204\351\227\256\351\242\230.md" "b/_posts/2025-02-17-\346\237\257\345\260\224\350\216\253\345\223\245\346\264\233\345\244\253\346\234\200\345\220\216\347\232\204\351\227\256\351\242\230.md" new file mode 100644 index 0000000..9a593cc --- /dev/null +++ "b/_posts/2025-02-17-\346\237\257\345\260\224\350\216\253\345\223\245\346\264\233\345\244\253\346\234\200\345\220\216\347\232\204\351\227\256\351\242\230.md" @@ -0,0 +1,61 @@ +柯尔莫哥洛夫(Andrey Kolmogorov)是概率论公理化体系的奠基人,他将概率定义为满足特定数学公理的非负函数(如非负性、规范性、可列可加性)。然而,他晚年提出的“概率在现实生活中意味着什么”这一问题,超越了数学形式化本身,触及了概率的**哲学本质**和**现实解释**。以下是分层次的解析: + +--- + +### 一、数学框架 vs 现实意义 +柯尔莫哥洛夫的**公理化体系**将概率抽象为数学对象,但它并未回答概率在现实中的本质。这类似于几何学中的“点”或“线”在数学上是明确定义的,但其物理意义需要额外解释。因此,概率的“现实意义”需结合不同学派和场景: + +--- + +### 二、概率的三大哲学解释 +1. **频率主义(Frequentism)** + - 观点:概率是长期重复事件中某结果出现的**极限频率**。 + - 例:抛硬币正面的概率是1/2,意味着无限次抛掷中正面占比趋近于50%。 + - 局限:无法解释单一事件(如“明天下雨的概率”)或不可重复事件(如“某场战争爆发的概率”)。 + +2. **贝叶斯主义(Bayesianism)** + - 观点:概率是**主观信念的量化**,反映个体基于现有信息的置信程度。 + - 例:医生根据患者症状判断患某病的概率为70%,这一概率会随新检查结果动态更新。 + - 优势:适用于信息不完整或独特事件,但主观性可能引发争议。 + +3. **倾向性解释(Propensity)** + - 观点:概率是物理系统内在的**客观倾向性**,如量子力学中粒子的行为。 + - 例:放射性原子衰变的概率由其物理属性决定,与观察者无关。 + - 争议:是否所有“随机性”都源于客观倾向?抛硬币的随机性可能只是混沌系统的结果。 + +--- + +### 三、现实生活中的概率意义 +1. **不确定性管理工具** + - 概率帮助量化未知,辅助决策(如保险定价、投资风险评估)。 + - 例:天气预报中“70%降水概率”可指导出行携带雨具的权衡。 + +2. **信息不完全的代理** + - 当系统过于复杂或信息有限时,概率作为简化模型存在。 + - 例:经济模型用概率描述市场波动,尽管背后可能由确定性因素驱动。 + +3. **科学与工程的基础语言** + - 从量子物理到机器学习,概率是描述随机性、噪声和统计规律的核心工具。 + - 例:深度学习中的“Dropout”技术通过随机屏蔽神经元防止过拟合。 + +--- + +### 四、柯尔莫哥洛夫问题的深层追问 +1. **概率是客观存在还是主观建构?** + - 量子力学支持客观概率,而社会现象中的概率更依赖主观解释。 + +2. **概率是否反映无知?** + - 拉普拉斯妖的困境:若已知宇宙所有粒子的状态,是否所有概率都会消失? + - 答案可能取决于物理世界是否本质随机(如量子不确定性)。 + +3. **公理化能否终结争论?** + - 柯尔莫哥洛夫的公理化统一了数学工具,但未解决哲学分歧——正如欧几里得几何无法解释“空间本质”。 + +--- + +### 五、总结:概率的现实意义是多元的 +- **数学工具**:公理化提供一致性框架。 +- **认知透镜**:频率派强调客观规律,贝叶斯派强调主观更新。 +- **实践语言**:跨越科学、金融、日常决策的通用“不确定性货币”。 + +柯尔莫哥洛夫的问题最终指向人类对**随机性与确定性边界**的永恒探索——概率既是理性的盾牌,也是面对未知的谦卑。 diff --git a/_posts/2025-02-26-ESLPod64.md b/_posts/2025-02-26-ESLPod64.md new file mode 100644 index 0000000..cc26e34 --- /dev/null +++ b/_posts/2025-02-26-ESLPod64.md @@ -0,0 +1,150 @@ +--- +layout: post +title: Bargain Rental Car +subtitle: ESLPod 74 +date: 2025-02-27 +author: 肖志勇 +header-img: img/bd1 +catalog: true +tags: + - ESLPod + +--- +### 原文 +I will be in Chicago next week and need a rental car. I called up Bargain Rental Car and made a reservation. After I got through the phone tree, I spoke with a reservation agent. + +Agent: Welcome to Bargain Rental Car. + +Jeff: I'd like to reserve a rental car. + +Agent: What city will you be picking up from? + +Jeff: Chicago. + +Agent: Which airport location? O'Hare or Midway? + +Jeff: Hmm. I'm not sure. Is there a downtown location? + +Agent: Sure. We have an office at 401 State Street. + +Jeff: Is that near Prairie State College? + +Agent: I really don't know. + +Jeff: That's okay. I'll go ahead and make a reservation for that location. + +Agent: For what date and time? + +Jeff: For November 11th, around 7 p.m. + +Agent: Returning to the same location? + +Jeff: No. I'd like to drop it off at the Chicago O'Hare airport. + +Agent: Okay. On what date and time? + +Jeff: It'll be that Sunday, November 13, around the same time. + +Agent: What size car would you like? A compact, mid-size, or full-size? + +Jeff: I'd like the most economical. + +Agent: That would be the compact. The rental fee would be $32.25 a day, giving you a grand total of $62.50 for the two days. + +Jeff: Does that include taxes and fees? + +Agent: No. With all applicable taxes and fees, you grand total comes to $77.40. + +Jeff: Okay, that's fine. + +Agent: Your last name? + +Jeff: McQuillan. M-C-Q-U-I-L-L-A-N. Agent: And your first name? + +Jeff: Jeff. + +Agent: J-E-S-S? + +Jeff: No, J-E-F, as in Frank, F. + +Agent: What credit card will you be using? + +Jeff: I'll be using a MasterCard. + +Agent: Okay, I have a compact reserved for pickup at our downtown location on the November 11 at 7 p.m., returning November 13 at 7 p.m. at Chicago O'Hare. Is there another reservation I can help you with? + +Jeff: No, that's all. Thanks. + +Agent: It's my pleasure. Have a good afternoon and thank you for calling Bargain Rental Car. + +--- + +### 翻译 + +下周我将前往芝加哥,需要租一辆车。我给 Bargain Rental Car 打了电话并预订了车辆。在通过电话自动应答系统后,我与一位预订代理进行了通话。 + +代理:欢迎致电 Bargain Rental Car。 + +杰夫:我想预订一辆租车。 + +代理:您将在哪个城市取车? + +杰夫:芝加哥。 + +代理:是哪个机场的位置?奥黑尔还是中途岛? + +杰夫:嗯,我不太确定。有市中心的位置吗? + +代理:当然有。我们在 State Street 401 号设有办事处。 + +杰夫:那离 Prairie State College 近吗? + +代理:我不太清楚。 + +杰夫:没关系。我还是先在那个地点预订吧。 + +代理:具体日期和时间是什么时候? + +杰夫:11 月 11 日,大约晚上 7 点。 + +代理:要在同一地点还车吗? + +杰夫:不,我想在芝加哥奥黑尔机场还车。 + +代理:好的。具体日期和时间是什么时候? + +杰夫:是 11 月 13 日,星期日,大约同一时间。 + +代理:您想要哪种尺寸的车?紧凑型、中型还是全尺寸? + +杰夫:我想要最经济的。 + +代理:那就是紧凑型。租车费用是每天 32.25 美元,两天的总费用是 62.50 美元。 + +杰夫:这包括税费和手续费了吗? + +代理:没有。加上所有适用的税费和手续费,您的总费用是 77.40 美元。 + +杰夫:好的,没问题。 + +代理:您的姓是什么? + +杰夫:McQuillan。M-C-Q-U-I-L-L-A-N。 + +代理:您的名字呢? + +杰夫:Jeff。 + +代理:J-E-S-S? + +杰夫:不是,是 J-E-F,就像 Frank 的 F 一样。 + +代理:您将使用哪张信用卡? + +杰夫:我将使用 MasterCard。 + +代理:好的,我已为您预订了一辆紧凑型车,11 月 11 日晚上 7 点在我们的市中心办事处取车,11 月 13 日晚上 7 点在芝加哥奥黑尔机场还车。还有其他预订需要帮忙吗? + +杰夫:没有了,谢谢。 + +代理:不客气。祝您下午愉快,感谢您致电 Bargain Rental Car。 diff --git a/about.html b/about.html index d298a05..d33e197 100644 --- a/about.html +++ b/about.html @@ -1,7 +1,7 @@ --- layout: page title: "About" -description: "「他单纯只想把日子过得不浪费」" +description: "「我怀念的是无话不说」" header-img: "img/home-bg-o.jpg" header-mask: 0 multilingual: true diff --git a/archive.html b/archive.html index 392be86..146a30f 100644 --- a/archive.html +++ b/archive.html @@ -1,7 +1,7 @@ --- title: Archive layout: default -description: "「我干了什么 究竟拿了时间换了什么」" +description: "「乘风好去,长空万里,直下看山河」" header-img: "img/bg-little-universe.jpg" --- diff --git a/img/bd1 b/img/bd1 new file mode 100644 index 0000000..e77bece Binary files /dev/null and b/img/bd1 differ diff --git "a/img/in-post/\346\241\202\346\236\227 (12).jpg" "b/img/in-post/\346\241\202\346\236\227 (12).jpg" new file mode 100644 index 0000000..fe48b39 Binary files /dev/null and "b/img/in-post/\346\241\202\346\236\227 (12).jpg" differ diff --git a/img/touxiang.jpg b/img/touxiang.jpg new file mode 100644 index 0000000..28396c7 Binary files /dev/null and b/img/touxiang.jpg differ diff --git a/index.html b/index.html index 5f5697a..20c2848 100644 --- a/index.html +++ b/index.html @@ -1,6 +1,6 @@ --- layout: page -description: "「我爱这生活。」" +description: "「我爱自己故我在!」" --- {% for post in paginator.posts %} diff --git a/myhtml.html b/myhtml.html new file mode 100644 index 0000000..9c4bc20 --- /dev/null +++ b/myhtml.html @@ -0,0 +1,19 @@ + + + + + + 桂影扶疏~ + + +

桂影扶疏~

+

欢迎来到我的个人页面!

+

这里是一些关于我的信息。

+
    +
  • 爱好:编程、阅读、旅行
  • +
  • 技能:HTML, CSS, JavaScript
  • +
  • 目标:成为一名全栈开发者
  • +
+

感谢您的访问!

+ + diff --git a/package-lock.json b/package-lock.json index 1b6c769..8b17ec7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,11 @@ { - "name": "lbx-blog", + "name": "xzy-blog", "version": "1.8.2", "lockfileVersion": 2, "requires": true, "packages": { "": { - "name": "lbx-blog", + "name": "xzy-blog", "version": "1.8.2", "devDependencies": { "grunt": ">=1.3.0", diff --git a/pwa/manifest.json b/pwa/manifest.json index 73fdb38..c263376 100644 --- a/pwa/manifest.json +++ b/pwa/manifest.json @@ -1,6 +1,6 @@ { - "name": "labixiong Blog", - "short_name": "Lbx Blog", + "name": "ZhiyongXiao Blog", + "short_name": "Xzy Blog", "description": "About an engineer & designer who loves web.", "icons": [{ "src": "icons/128.png",