-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathb539f3fa.html
184 lines (171 loc) · 48.9 KB
/
b539f3fa.html
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
<!DOCTYPE html><html lang="zh-CN" data-theme="light"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"><title>给SpringCloud-Gateway加全局过滤器,添加请求日志 | 实现一个小目标</title><meta name="keywords" content="Java,Spring,SpringCloud"><meta name="author" content="我想打游戏,[email protected]"><meta name="copyright" content="我想打游戏"><meta name="format-detection" content="telephone=no"><meta name="theme-color" content="#ffffff"><meta name="description" content="给Gateway加全局过滤器,添加请求日志">
<meta property="og:type" content="article">
<meta property="og:title" content="给SpringCloud-Gateway加全局过滤器,添加请求日志">
<meta property="og:url" content="https://blog.990304.xyz/b539f3fa.html">
<meta property="og:site_name" content="实现一个小目标">
<meta property="og:description" content="给Gateway加全局过滤器,添加请求日志">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://img-blog.csdnimg.cn/c29e31f0bab84722983c71f6ce6144aa.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAcXFfMzAwODczOTU=,size_14,color_FFFFFF,t_70,g_se,x_16#pic_center">
<meta property="article:published_time" content="2022-01-07T07:05:37.000Z">
<meta property="article:modified_time" content="2023-02-02T02:41:43.301Z">
<meta property="article:author" content="我想打游戏">
<meta property="article:tag" content="Java">
<meta property="article:tag" content="Spring">
<meta property="article:tag" content="SpringCloud">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://img-blog.csdnimg.cn/c29e31f0bab84722983c71f6ce6144aa.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAcXFfMzAwODczOTU=,size_14,color_FFFFFF,t_70,g_se,x_16#pic_center"><link rel="shortcut icon" href="/img/favicon.png"><link rel="canonical" href="https://blog.990304.xyz/b539f3fa"><link rel="preconnect" href="//cdn.jsdelivr.net"/><link rel="preconnect" href="//hm.baidu.com"/><link rel="preconnect" href="//busuanzi.ibruce.info"/><link rel="stylesheet" href="/css/index.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free/css/all.min.css" media="print" onload="this.media='all'"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/ui/dist/fancybox.min.css" media="print" onload="this.media='all'"><script>var _hmt = _hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?a6a8fe63a57ca303dd1117df5f602aec";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script><script>const GLOBAL_CONFIG = {
root: '/',
algolia: undefined,
localSearch: undefined,
translate: {"defaultEncoding":1,"translateDelay":0,"msgToTraditionalChinese":"繁","msgToSimplifiedChinese":"简"},
noticeOutdate: undefined,
highlight: {"plugin":"highlighjs","highlightCopy":true,"highlightLang":true,"highlightHeightLimit":false},
copy: {
success: '复制成功',
error: '复制错误',
noSupport: '浏览器不支持'
},
relativeDate: {
homepage: true,
post: true
},
runtime: '天',
date_suffix: {
just: '刚刚',
min: '分钟前',
hour: '小时前',
day: '天前',
month: '个月前'
},
copyright: undefined,
lightbox: 'fancybox',
Snackbar: undefined,
source: {
justifiedGallery: {
js: 'https://cdn.jsdelivr.net/npm/flickr-justified-gallery/dist/fjGallery.min.js',
css: 'https://cdn.jsdelivr.net/npm/flickr-justified-gallery/dist/fjGallery.min.css'
}
},
isPhotoFigcaption: true,
islazyload: false,
isAnchor: true
}</script><script id="config-diff">var GLOBAL_CONFIG_SITE = {
title: '给SpringCloud-Gateway加全局过滤器,添加请求日志',
isPost: true,
isHome: false,
isHighlightShrink: false,
isToc: true,
postUpdate: '2023-02-02 10:41:43'
}</script><noscript><style type="text/css">
#nav {
opacity: 1
}
.justified-gallery img {
opacity: 1
}
#recent-posts time,
#post-meta time {
display: inline !important
}
</style></noscript><script>(win=>{
win.saveToLocal = {
set: function setWithExpiry(key, value, ttl) {
if (ttl === 0) return
const now = new Date()
const expiryDay = ttl * 86400000
const item = {
value: value,
expiry: now.getTime() + expiryDay,
}
localStorage.setItem(key, JSON.stringify(item))
},
get: function getWithExpiry(key) {
const itemStr = localStorage.getItem(key)
if (!itemStr) {
return undefined
}
const item = JSON.parse(itemStr)
const now = new Date()
if (now.getTime() > item.expiry) {
localStorage.removeItem(key)
return undefined
}
return item.value
}
}
win.getScript = url => new Promise((resolve, reject) => {
const script = document.createElement('script')
script.src = url
script.async = true
script.onerror = reject
script.onload = script.onreadystatechange = function() {
const loadState = this.readyState
if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
script.onload = script.onreadystatechange = null
resolve()
}
document.head.appendChild(script)
})
win.activateDarkMode = function () {
document.documentElement.setAttribute('data-theme', 'dark')
if (document.querySelector('meta[name="theme-color"]') !== null) {
document.querySelector('meta[name="theme-color"]').setAttribute('content', '#0d0d0d')
}
}
win.activateLightMode = function () {
document.documentElement.setAttribute('data-theme', 'light')
if (document.querySelector('meta[name="theme-color"]') !== null) {
document.querySelector('meta[name="theme-color"]').setAttribute('content', '#ffffff')
}
}
const t = saveToLocal.get('theme')
if (t === 'dark') activateDarkMode()
else if (t === 'light') activateLightMode()
const asideStatus = saveToLocal.get('aside-status')
if (asideStatus !== undefined) {
if (asideStatus === 'hide') {
document.documentElement.classList.add('hide-aside')
} else {
document.documentElement.classList.remove('hide-aside')
}
}
const detectApple = () => {
if(/iPad|iPhone|iPod|Macintosh/.test(navigator.userAgent)){
document.documentElement.classList.add('apple')
}
}
detectApple()
})(window)</script><meta name="generator" content="Hexo 6.3.0"></head><body><div id="sidebar"><div id="menu-mask"></div><div id="sidebar-menus"><div class="avatar-img is-center"><img src="https://s2.loli.net/2022/09/28/iEBxunMYAGHODFz.jpg" onerror="onerror=null;src='/img/friend_404.gif'" alt="avatar"/></div><div class="sidebar-site-data site-data is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">20</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">6</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">6</div></a></div><hr/><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 主页</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 时间轴</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page group" href="javascript:void(0);"><i class="fa-fw fas fa-list"></i><span> 清单</span><i class="fas fa-chevron-down"></i></a><ul class="menus_item_child"><li><a class="site-page child" href="/music/"><i class="fa-fw fas fa-music"></i><span> 音乐</span></a></li><li><a class="site-page child" href="/movies/"><i class="fa-fw fas fa-video"></i><span> 电影</span></a></li></ul></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> 友情链接</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-heart"></i><span> 关于</span></a></div></div></div></div><div class="post" id="body-wrap"><header class="post-bg" id="page-header" style="background-image: url('https://img-blog.csdnimg.cn/c29e31f0bab84722983c71f6ce6144aa.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAcXFfMzAwODczOTU=,size_14,color_FFFFFF,t_70,g_se,x_16#pic_center')"><nav id="nav"><span id="blog_name"><a id="site-name" href="/">实现一个小目标</a></span><div id="menus"><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 主页</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 时间轴</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page group" href="javascript:void(0);"><i class="fa-fw fas fa-list"></i><span> 清单</span><i class="fas fa-chevron-down"></i></a><ul class="menus_item_child"><li><a class="site-page child" href="/music/"><i class="fa-fw fas fa-music"></i><span> 音乐</span></a></li><li><a class="site-page child" href="/movies/"><i class="fa-fw fas fa-video"></i><span> 电影</span></a></li></ul></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> 友情链接</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-heart"></i><span> 关于</span></a></div></div><div id="toggle-menu"><a class="site-page"><i class="fas fa-bars fa-fw"></i></a></div></div></nav><div id="post-info"><h1 class="post-title">给SpringCloud-Gateway加全局过滤器,添加请求日志</h1><div id="post-meta"><div class="meta-firstline"><span class="post-meta-date"><i class="far fa-calendar-alt fa-fw post-meta-icon"></i><span class="post-meta-label">发表于</span><time class="post-meta-date-created" datetime="2022-01-07T07:05:37.000Z" title="发表于 2022-01-07 15:05:37">2022-01-07</time><span class="post-meta-separator">|</span><i class="fas fa-history fa-fw post-meta-icon"></i><span class="post-meta-label">更新于</span><time class="post-meta-date-updated" datetime="2023-02-02T02:41:43.301Z" title="更新于 2023-02-02 10:41:43">2023-02-02</time></span><span class="post-meta-categories"><span class="post-meta-separator">|</span><i class="fas fa-inbox fa-fw post-meta-icon"></i><a class="post-meta-categories" href="/categories/Java-%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/">Java 学习笔记</a></span></div><div class="meta-secondline"><span class="post-meta-separator">|</span><span class="post-meta-wordcount"><i class="far fa-file-word fa-fw post-meta-icon"></i><span class="post-meta-label">字数总计:</span><span class="word-count">1.2k</span><span class="post-meta-separator">|</span><i class="far fa-clock fa-fw post-meta-icon"></i><span class="post-meta-label">阅读时长:</span><span>5分钟</span></span><span class="post-meta-separator">|</span><span class="post-meta-pv-cv" id="" data-flag-title="给SpringCloud-Gateway加全局过滤器,添加请求日志"><i class="far fa-eye fa-fw post-meta-icon"></i><span class="post-meta-label">阅读量:</span><span id="busuanzi_value_page_pv"><i class="fa-solid fa-spinner fa-spin"></i></span></span></div></div></div></header><main class="layout" id="content-inner"><div id="post"><article class="post-content" id="article-container"><h1 id="先上代码"><a href="#先上代码" class="headerlink" title="先上代码"></a>先上代码</h1><h2 id="代码结构:"><a href="#代码结构:" class="headerlink" title="代码结构:"></a>代码结构:</h2><p><img src="https://img-blog.csdnimg.cn/c29e31f0bab84722983c71f6ce6144aa.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAcXFfMzAwODczOTU=,size_14,color_FFFFFF,t_70,g_se,x_16#pic_center"></p>
<h2 id="具体代码"><a href="#具体代码" class="headerlink" title="具体代码"></a>具体代码</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.litianyi.supermall.gateway.filters;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.litianyi.supermall.gateway.context.BaseContextHandler;</span><br><span class="line"><span class="keyword">import</span> lombok.extern.slf4j.Slf4j;</span><br><span class="line"><span class="keyword">import</span> org.springframework.cloud.gateway.filter.GatewayFilterChain;</span><br><span class="line"><span class="keyword">import</span> org.springframework.cloud.gateway.filter.GlobalFilter;</span><br><span class="line"><span class="keyword">import</span> org.springframework.core.Ordered;</span><br><span class="line"><span class="keyword">import</span> org.springframework.http.server.reactive.ServerHttpRequest;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Component;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.server.ServerWebExchange;</span><br><span class="line"><span class="keyword">import</span> reactor.core.publisher.Mono;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.time.Instant;</span><br><span class="line"><span class="keyword">import</span> java.util.stream.Collectors;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> litianyi</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@version</span> 1.0</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@date</span> 2022/1/7 12:19 PM</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">GlobalStartLoggerFilter</span> <span class="keyword">implements</span> <span class="title class_">GlobalFilter</span>, Ordered {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">startLogInfo</span><span class="params">(ServerWebExchange exchange)</span> {</span><br><span class="line"> <span class="type">ServerHttpRequest</span> <span class="variable">request</span> <span class="operator">=</span> exchange.getRequest();</span><br><span class="line"></span><br><span class="line"> <span class="type">String</span> <span class="variable">url</span> <span class="operator">=</span> request.getURI().toString();</span><br><span class="line"> <span class="type">String</span> <span class="variable">params</span> <span class="operator">=</span> request.getQueryParams().toString();</span><br><span class="line"> <span class="type">String</span> <span class="variable">method</span> <span class="operator">=</span> request.getMethodValue();</span><br><span class="line"> <span class="type">String</span> <span class="variable">headers</span> <span class="operator">=</span> request.getHeaders().entrySet().stream()</span><br><span class="line"> .map(entry -> entry.getKey() + <span class="string">": ["</span> + String.join(<span class="string">";"</span>, entry.getValue()) + <span class="string">"]"</span>)</span><br><span class="line"> .collect(Collectors.joining(<span class="string">"\n\t"</span>));</span><br><span class="line"></span><br><span class="line"> <span class="type">StringBuilder</span> <span class="variable">builder</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">StringBuilder</span>();</span><br><span class="line"> builder.append(<span class="string">"****************************************请求路径:[{}]请求开始****************************************\n"</span>);</span><br><span class="line"> builder.append(<span class="string">"url: "</span> + url + <span class="string">"\n"</span>);</span><br><span class="line"> builder.append(<span class="string">"gateway_request_url: "</span> + exchange.getRequiredAttribute(GATEWAY_REQUEST_URL_ATTR) + <span class="string">"\n"</span>);</span><br><span class="line"> builder.append(<span class="string">"method: "</span> + method + <span class="string">"\n"</span>);</span><br><span class="line"> builder.append(<span class="string">"params: "</span> + params + <span class="string">"\n"</span>);</span><br><span class="line"> builder.append(<span class="string">"headers: \n{ \n"</span> + headers + <span class="string">" \n}\n"</span>);</span><br><span class="line"> log.info(String.valueOf(builder), url);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> Mono<Void> <span class="title function_">filter</span><span class="params">(ServerWebExchange exchange, GatewayFilterChain chain)</span> {</span><br><span class="line"></span><br><span class="line"> <span class="comment">//前置过滤</span></span><br><span class="line"> BaseContextHandler.getContextMap().put(<span class="string">"beginTime"</span>, Instant.now());</span><br><span class="line"> <span class="built_in">this</span>.startLogInfo(exchange);</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> chain.filter(exchange);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">getOrder</span><span class="params">()</span> {</span><br><span class="line"> <span class="keyword">return</span> HIGHEST_PRECEDENCE;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.litianyi.supermall.gateway.filters;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> com.litianyi.supermall.gateway.context.BaseContextHandler;</span><br><span class="line"><span class="keyword">import</span> lombok.extern.slf4j.Slf4j;</span><br><span class="line"><span class="keyword">import</span> org.springframework.cloud.gateway.filter.GatewayFilterChain;</span><br><span class="line"><span class="keyword">import</span> org.springframework.cloud.gateway.filter.GlobalFilter;</span><br><span class="line"><span class="keyword">import</span> org.springframework.core.Ordered;</span><br><span class="line"><span class="keyword">import</span> org.springframework.http.server.reactive.ServerHttpRequest;</span><br><span class="line"><span class="keyword">import</span> org.springframework.stereotype.Component;</span><br><span class="line"><span class="keyword">import</span> org.springframework.web.server.ServerWebExchange;</span><br><span class="line"><span class="keyword">import</span> reactor.core.publisher.Mono;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.time.Duration;</span><br><span class="line"><span class="keyword">import</span> java.time.Instant;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> <span class="keyword">static</span> org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> litianyi</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@version</span> 1.0</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@date</span> 2022/1/7 12:19 PM</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="meta">@Component</span></span><br><span class="line"><span class="meta">@Slf4j</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">GlobalEndLoggerFilter</span> <span class="keyword">implements</span> <span class="title class_">GlobalFilter</span>, Ordered {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">void</span> <span class="title function_">endLogInfo</span><span class="params">(ServerWebExchange exchange, <span class="type">long</span> time)</span> {</span><br><span class="line"> <span class="type">ServerHttpRequest</span> <span class="variable">request</span> <span class="operator">=</span> exchange.getRequest();</span><br><span class="line"> <span class="type">String</span> <span class="variable">url</span> <span class="operator">=</span> request.getURI().toString();</span><br><span class="line"> <span class="type">String</span> <span class="variable">attribute</span> <span class="operator">=</span> exchange.getRequiredAttribute(GATEWAY_REQUEST_URL_ATTR).toString();</span><br><span class="line"></span><br><span class="line"> <span class="type">StringBuilder</span> <span class="variable">builder</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">StringBuilder</span>();</span><br><span class="line"> builder.append(<span class="string">"****************************************请求路径:[{}]请求结束, 耗时:[{}]ms****************************************\n"</span>);</span><br><span class="line"> builder.append(<span class="string">"gateway_request_url: "</span> + attribute + <span class="string">"\n"</span>);</span><br><span class="line"> log.info(String.valueOf(builder), url, time);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> Mono<Void> <span class="title function_">filter</span><span class="params">(ServerWebExchange exchange, GatewayFilterChain chain)</span> {</span><br><span class="line"></span><br><span class="line"> <span class="comment">//后置过滤</span></span><br><span class="line"> <span class="type">Instant</span> <span class="variable">instant</span> <span class="operator">=</span> (Instant) BaseContextHandler.getContextMap().get(<span class="string">"beginTime"</span>);</span><br><span class="line"> endLogInfo(exchange, Duration.between(instant, Instant.now()).toMillis());</span><br><span class="line"> BaseContextHandler.remove();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> chain.filter(exchange);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="meta">@Override</span></span><br><span class="line"> <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">getOrder</span><span class="params">()</span> {</span><br><span class="line"> <span class="keyword">return</span> LOWEST_PRECEDENCE;</span><br><span class="line"> }</span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<p>这个类是为了获取运行时间,也可以使用其他方式获取运行时间。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">package</span> com.litianyi.supermall.gateway.context;</span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> java.util.HashMap;</span><br><span class="line"><span class="keyword">import</span> java.util.Map;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@author</span> litianyi</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">BaseContextHandler</span> {</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">final</span> ThreadLocal<Map<String, Object>> threadContext = ThreadLocal.withInitial(() -> <span class="keyword">new</span> <span class="title class_">HashMap</span><>());</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="title function_">BaseContextHandler</span><span class="params">()</span> {</span><br><span class="line"></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 取得thread context Map的实例。</span></span><br><span class="line"><span class="comment"> *</span></span><br><span class="line"><span class="comment"> * <span class="doctag">@return</span> thread context Map的实例</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> Map<String, Object> <span class="title function_">getContextMap</span><span class="params">()</span> {</span><br><span class="line"> <span class="keyword">return</span> threadContext.get();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">remove</span><span class="params">()</span> {</span><br><span class="line"> getContextMap().clear();</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line">}</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<h2 id="运行效果"><a href="#运行效果" class="headerlink" title="运行效果"></a>运行效果</h2><p><img src="https://img-blog.csdnimg.cn/c69ec7e6ab7944099c9df151305f7173.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAcXFfMzAwODczOTU=,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center"></p>
<h1 id="解决方法"><a href="#解决方法" class="headerlink" title="解决方法"></a>解决方法</h1><p>在使用 Gateway 的时候,不确定自己写的 predicates 和 filters 是否正确,想要知道经过 Gateway 过滤器后真正的请求是什么,有两种方法,一种是debug查看真实的url,另一种就是使用日志,把转发后的 url 打印出来。</p>
<h2 id="阅读源码:"><a href="#阅读源码:" class="headerlink" title="阅读源码:"></a>阅读源码:</h2><h3 id="对-RouteToRequestUrlFilter-进行-debug"><a href="#对-RouteToRequestUrlFilter-进行-debug" class="headerlink" title="对 RouteToRequestUrlFilter 进行 debug"></a>对 RouteToRequestUrlFilter 进行 debug</h3><p>从 GatewayAutoConfiguration 可以看到他运行了 RouteToRequestUrlFilter 类,这个类就是 Gateway 确定路由到哪个服务地址的类。<br><img src="https://img-blog.csdnimg.cn/4e0128f2d994453cae12dd14edc8277d.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAcXFfMzAwODczOTU=,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center"></p>
<p>进入这个类,进行debug<br><img src="https://img-blog.csdnimg.cn/a0ac565dcab243bda47dec4a13644d53.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAcXFfMzAwODczOTU=,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center"></p>
<blockquote>
<p>lb:load balancer 负载均衡</p>
</blockquote>
<p>可以看到,RouteToRequestUrlFilter 把确定了服务的 url 使用 GATEWAY_REQUEST_URL_ATTR 这个 key 保存到了 ServerWebExchange 对象的 Attributes 里。</p>
<p>接下来进入负载均衡过滤器</p>
<h3 id="对-LoadBalancerClientFilter-进行debug"><a href="#对-LoadBalancerClientFilter-进行debug" class="headerlink" title="对 LoadBalancerClientFilter 进行debug"></a>对 LoadBalancerClientFilter 进行debug</h3><p><img src="https://img-blog.csdnimg.cn/1b564e14129847de8544c5548e61cdb7.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAcXFfMzAwODczOTU=,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center"></p>
<p>经过负载均衡过滤器确定了真正要请求的url,然后又使用 GATEWAY_REQUEST_URL_ATTR 这个 key 存到了 ServerWebExchange 对象的 Attributes 里。</p>
<p>经过这一波操作,写日志的思路就有了。</p>
<h2 id="写日志:"><a href="#写日志:" class="headerlink" title="写日志:"></a>写日志:</h2><p>Gateway 的过滤器有两种,一种是<strong>全局过滤器</strong>,另一种是针对于 Router 的过滤器(Gateway提供了丰富的 router 过滤器,本文不涉及自定义这种过滤器)。<br>全局过滤器不需要工厂,也不需要配置,直接对所有的路由都生效。可以使用<strong>全局过滤器</strong>实现统一的权限验证、日志记录等希望对所有代理的项目都生效的内容,可以配置在全局过滤器中。<br>且在项目中可以配置多个<strong>全局过滤器</strong>的实现类,都可以自动执行。</p>
<h3 id="自定义的全局过滤器需要实现-GlobalFilter-和-Ordered。"><a href="#自定义的全局过滤器需要实现-GlobalFilter-和-Ordered。" class="headerlink" title="自定义的全局过滤器需要实现 GlobalFilter 和 Ordered。"></a>自定义的全局过滤器需要实现 GlobalFilter 和 Ordered。</h3><p>主要的日志逻辑可以写在需要实现的 GlobalFilter 下的 public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) 方法内。</p>
<blockquote>
<p>ServerWebExchange 类的解释: Contract for an HTTP request-response interaction. Provides access to the HTTP request and response and also exposes additional server-side processing related properties and features such as request attributes.<br>HTTP 请求-响应交互的契约。 提供对 HTTP 请求和响应的访问,还公开其他与服务器端处理相关的属性和功能,例如请求属性。</p>
</blockquote>
<p>Ordered 需要实现 public int getOrder() 方法。改方法返回一个int,表示这个filter的执行顺序。</p>
<blockquote>
<p>Ordered 类的解释: Ordered is an interface that can be implemented by objects that should be orderable, for example in a Collection.<br>The actual order can be interpreted as prioritization, with the first object (with the lowest order value) having the highest priority.<br>实际order可以解释为优先级,第一个对象(具有最低顺序值)具有最高优先级。</p>
</blockquote>
</article><div class="post-copyright"><div class="post-copyright__author"><span class="post-copyright-meta">文章作者: </span><span class="post-copyright-info"><a href="https://blog.990304.xyz">我想打游戏</a></span></div><div class="post-copyright__type"><span class="post-copyright-meta">文章链接: </span><span class="post-copyright-info"><a href="https://blog.990304.xyz/b539f3fa.html">https://blog.990304.xyz/b539f3fa.html</a></span></div><div class="post-copyright__notice"><span class="post-copyright-meta">版权声明: </span><span class="post-copyright-info">本博客所有文章除特别声明外,均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank">CC BY-NC-SA 4.0</a> 许可协议。转载请注明来自 <a href="https://blog.990304.xyz" target="_blank">实现一个小目标</a>!</span></div></div><div class="tag_share"><div class="post-meta__tag-list"><a class="post-meta__tags" href="/tags/Java/">Java</a><a class="post-meta__tags" href="/tags/Spring/">Spring</a><a class="post-meta__tags" href="/tags/SpringCloud/">SpringCloud</a></div><div class="post_share"><div class="social-share" data-image="https://img-blog.csdnimg.cn/c29e31f0bab84722983c71f6ce6144aa.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAcXFfMzAwODczOTU=,size_14,color_FFFFFF,t_70,g_se,x_16#pic_center" data-sites="facebook,twitter,wechat,weibo,qq"></div><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/butterfly-extsrc/sharejs/dist/css/share.min.css" media="print" onload="this.media='all'"><script src="https://cdn.jsdelivr.net/npm/butterfly-extsrc/sharejs/dist/js/social-share.min.js" defer></script></div></div><nav class="pagination-post" id="pagination"><div class="prev-post pull-full"><a href="/b8228d97.html"><img class="prev-cover" src="https://img-blog.csdnimg.cn/df0486e7b51f4b5aa1b9234b24dc266a.png" onerror="onerror=null;src='/img/404.jpg'" alt="cover of previous post"><div class="pagination-info"><div class="label">上一篇</div><div class="prev_info">Spring 入门</div></div></a></div></nav><div class="relatedPosts"><div class="headline"><i class="fas fa-thumbs-up fa-fw"></i><span>相关推荐</span></div><div class="relatedPosts-list"><div><a href="/aad19206.html" title="Bean 创建流程"><img class="cover" src="https://s2.loli.net/2022/10/08/8REn1yjfUVaKosF.png" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2022-06-21</div><div class="title">Bean 创建流程</div></div></a></div><div><a href="/7aea873f.html" title="BeanFactory 创建流程"><img class="cover" src="https://s2.loli.net/2022/10/08/1TbhpYeOIfgsU3Q.png" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2022-06-18</div><div class="title">BeanFactory 创建流程</div></div></a></div><div><a href="/690a266d.html" title="Spring IoC 容器初始化主体流程"><img class="cover" src="https://img-blog.csdnimg.cn/1b40502ab717476ba8ee7df0931ea527.png" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2022-06-15</div><div class="title">Spring IoC 容器初始化主体流程</div></div></a></div><div><a href="/655d86b3.html" title="Spring AOP"><img class="cover" src="https://s2.loli.net/2022/10/09/IoNOM4PifrBpZ67.png" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2022-03-21</div><div class="title">Spring AOP</div></div></a></div><div><a href="/adc3e213.html" title="Spring Bean 的作用范围及生命周期"><img class="cover" src="https://img-blog.csdnimg.cn/46d42e4c19b2427da2b3e31453263650.png" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2022-05-19</div><div class="title">Spring Bean 的作用范围及生命周期</div></div></a></div><div><a href="/cbde7b0b.html" title="Spring IoC 循环依赖问题"><img class="cover" src="https://img-blog.csdnimg.cn/3aa3e44f116944ef9b10b4dd735c156a.png" alt="cover"><div class="content is-center"><div class="date"><i class="far fa-calendar-alt fa-fw"></i> 2022-07-30</div><div class="title">Spring IoC 循环依赖问题</div></div></a></div></div></div></div><div class="aside-content" id="aside-content"><div class="card-widget card-info"><div class="is-center"><div class="avatar-img"><img src="https://s2.loli.net/2022/09/28/iEBxunMYAGHODFz.jpg" onerror="this.onerror=null;this.src='/img/friend_404.gif'" alt="avatar"/></div><div class="author-info__name">我想打游戏</div><div class="author-info__description">记录一些生活趣事</div></div><div class="card-info-data site-data is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">20</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">6</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">6</div></a></div><a id="card-info-btn" target="_blank" rel="noopener" href="https://github.com/guziwen-lab"><i class="fab fa-github"></i><span>Follow Me</span></a><div class="card-info-social-icons is-center"><a class="social-icon" href="https://github.com/guziwen-lab/" target="_blank" title="Github"><i class="fab fa-github"></i></a><a class="social-icon" href="mailto:[email protected]" target="_blank" title="Email"><i class="fas fa-envelope"></i></a><a class="social-icon" href="https://blog.csdn.net/qq_30087395/" target="_blank" title="Csdn"><i class="fa-solid fa-rss"></i></a></div></div><div class="card-widget card-announcement"><div class="item-headline"><i class="fas fa-bullhorn fa-shake"></i><span>公告</span></div><div class="announcement_content">欢迎大家</div></div><div class="sticky_layout"><div class="card-widget" id="card-toc"><div class="item-headline"><i class="fas fa-stream"></i><span>目录</span><span class="toc-percentage"></span></div><div class="toc-content"><ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#%E5%85%88%E4%B8%8A%E4%BB%A3%E7%A0%81"><span class="toc-number">1.</span> <span class="toc-text">先上代码</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%BB%A3%E7%A0%81%E7%BB%93%E6%9E%84%EF%BC%9A"><span class="toc-number">1.1.</span> <span class="toc-text">代码结构:</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%85%B7%E4%BD%93%E4%BB%A3%E7%A0%81"><span class="toc-number">1.2.</span> <span class="toc-text">具体代码</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E8%BF%90%E8%A1%8C%E6%95%88%E6%9E%9C"><span class="toc-number">1.3.</span> <span class="toc-text">运行效果</span></a></li></ol></li><li class="toc-item toc-level-1"><a class="toc-link" href="#%E8%A7%A3%E5%86%B3%E6%96%B9%E6%B3%95"><span class="toc-number">2.</span> <span class="toc-text">解决方法</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E9%98%85%E8%AF%BB%E6%BA%90%E7%A0%81%EF%BC%9A"><span class="toc-number">2.1.</span> <span class="toc-text">阅读源码:</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%AF%B9-RouteToRequestUrlFilter-%E8%BF%9B%E8%A1%8C-debug"><span class="toc-number">2.1.1.</span> <span class="toc-text">对 RouteToRequestUrlFilter 进行 debug</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%AF%B9-LoadBalancerClientFilter-%E8%BF%9B%E8%A1%8Cdebug"><span class="toc-number">2.1.2.</span> <span class="toc-text">对 LoadBalancerClientFilter 进行debug</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%86%99%E6%97%A5%E5%BF%97%EF%BC%9A"><span class="toc-number">2.2.</span> <span class="toc-text">写日志:</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%87%AA%E5%AE%9A%E4%B9%89%E7%9A%84%E5%85%A8%E5%B1%80%E8%BF%87%E6%BB%A4%E5%99%A8%E9%9C%80%E8%A6%81%E5%AE%9E%E7%8E%B0-GlobalFilter-%E5%92%8C-Ordered%E3%80%82"><span class="toc-number">2.2.1.</span> <span class="toc-text">自定义的全局过滤器需要实现 GlobalFilter 和 Ordered。</span></a></li></ol></li></ol></li></ol></div></div><div class="card-widget card-recent-post"><div class="item-headline"><i class="fas fa-history"></i><span>最新文章</span></div><div class="aside-list"><div class="aside-list-item"><a class="thumbnail" href="/6e9746c4.html" title="CentOS 安装翰高数据库"><img src="https://s2.loli.net/2023/03/13/UucfkBIRYxCd7Tm.png" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="CentOS 安装翰高数据库"/></a><div class="content"><a class="title" href="/6e9746c4.html" title="CentOS 安装翰高数据库">CentOS 安装翰高数据库</a><time datetime="2023-03-13T08:08:54.000Z" title="发表于 2023-03-13 16:08:54">2023-03-13</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/e56c5c4.html" title="可移动硬盘内的AppImage应用如何获取移动硬盘内的资源"><img src="https://s2.loli.net/2022/10/01/fnwLNigZCUG7bTd.jpg" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="可移动硬盘内的AppImage应用如何获取移动硬盘内的资源"/></a><div class="content"><a class="title" href="/e56c5c4.html" title="可移动硬盘内的AppImage应用如何获取移动硬盘内的资源">可移动硬盘内的AppImage应用如何获取移动硬盘内的资源</a><time datetime="2023-02-02T03:31:45.000Z" title="发表于 2023-02-02 11:31:45">2023-02-02</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/49140f59.html" title="把Java程序打包为AppImage格式"><img src="https://s2.loli.net/2023/01/12/SczgAwsmhU3ltF4.png" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="把Java程序打包为AppImage格式"/></a><div class="content"><a class="title" href="/49140f59.html" title="把Java程序打包为AppImage格式">把Java程序打包为AppImage格式</a><time datetime="2023-01-12T01:09:32.000Z" title="发表于 2023-01-12 09:09:32">2023-01-12</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/ff0917f7.html" title="流量控制与可靠传输"><img src="https://s2.loli.net/2022/10/04/EQqN6dK9YDFJmhj.png" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="流量控制与可靠传输"/></a><div class="content"><a class="title" href="/ff0917f7.html" title="流量控制与可靠传输">流量控制与可靠传输</a><time datetime="2022-10-04T15:00:44.000Z" title="发表于 2022-10-04 23:00:44">2022-10-04</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/a5d2d7c3.html" title="Mybaits 架构原理"><img src="https://s2.loli.net/2022/10/01/46p5Emr3uRMd7vo.png" onerror="this.onerror=null;this.src='/img/404.jpg'" alt="Mybaits 架构原理"/></a><div class="content"><a class="title" href="/a5d2d7c3.html" title="Mybaits 架构原理">Mybaits 架构原理</a><time datetime="2022-10-01T05:24:18.000Z" title="发表于 2022-10-01 13:24:18">2022-10-01</time></div></div></div></div></div></div></main><footer id="footer"><div id="footer-wrap"><div class="copyright">©2022 - 2023 By 我想打游戏</div><div class="framework-info"><span>框架 </span><a target="_blank" rel="noopener" href="https://hexo.io">Hexo</a><span class="footer-separator">|</span><span>主题 </span><a target="_blank" rel="noopener" href="https://github.com/jerryc127/hexo-theme-butterfly">Butterfly</a></div></div></footer></div><div id="rightside"><div id="rightside-config-hide"><button id="readmode" type="button" title="阅读模式"><i class="fas fa-book-open"></i></button><button id="translateLink" type="button" title="简繁转换">简</button><button id="darkmode" type="button" title="浅色和深色模式转换"><i class="fas fa-adjust"></i></button><button id="hide-aside-btn" type="button" title="单栏和双栏切换"><i class="fas fa-arrows-alt-h"></i></button></div><div id="rightside-config-show"><button id="rightside_config" type="button" title="设置"><i class="fas fa-cog fa-spin"></i></button><button class="close" id="mobile-toc-button" type="button" title="目录"><i class="fas fa-list-ul"></i></button><button id="go-up" type="button" title="回到顶部"><i class="fas fa-arrow-up"></i></button></div></div><div><script src="/js/utils.js"></script><script src="/js/main.js"></script><script src="/js/tw_cn.js"></script><script src="https://cdn.jsdelivr.net/npm/@fancyapps/ui/dist/fancybox.umd.min.js"></script><div class="js-pjax"></div><script async data-pjax src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script></div></body></html>