<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <author>
    <name>JCAlways</name>
  </author>
  <generator uri="https://hexo.io/">Hexo</generator>
  <id>https://blog.zhangsifan.com/</id>
  <link href="https://blog.zhangsifan.com/" rel="alternate"/>
  <link href="https://blog.zhangsifan.com/atom.xml" rel="self"/>
  <rights>All rights reserved 2026, JCAlways</rights>
  <subtitle>分享开发过程中遇到的问题,以及一些技术文章!</subtitle>
  <title>JCAlways</title>
  <updated>2026-03-31T03:22:20.637Z</updated>
  <entry>
    <author>
      <name>JCAlways</name>
    </author>
    <category term="OnlyOffice" scheme="https://blog.zhangsifan.com/categories/OnlyOffice/"/>
    <category term="OnlyOffice" scheme="https://blog.zhangsifan.com/tags/OnlyOffice/"/>
    <content>
      <![CDATA[<h1 id="前端使用"><a href="#前端使用" class="headerlink" title="前端使用"></a>前端使用</h1><figure class="highlight html"><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><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">html</span> <span class="attr">lang</span>=<span class="string">&quot;en&quot;</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">charset</span>=<span class="string">&quot;UTF-8&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">meta</span> <span class="attr">name</span>=<span class="string">&quot;viewport&quot;</span> <span class="attr">content</span>=<span class="string">&quot;width=device-width, initial-scale=1.0&quot;</span> /&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">title</span>&gt;</span>OnlyOffice<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">style</span>&gt;</span><span class="language-css"></span></span><br><span class="line"><span class="language-css">      <span class="selector-tag">html</span>,</span></span><br><span class="line"><span class="language-css">      <span class="selector-tag">body</span> &#123;</span></span><br><span class="line"><span class="language-css">        <span class="attribute">padding</span>: <span class="number">0</span>;</span></span><br><span class="line"><span class="language-css">        <span class="attribute">margin</span>: <span class="number">0</span>;</span></span><br><span class="line"><span class="language-css">      &#125;</span></span><br><span class="line"><span class="language-css">    </span><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span></span></span><br><span class="line"><span class="tag">      <span class="attr">type</span>=<span class="string">&quot;text/javascript&quot;</span></span></span><br><span class="line"><span class="tag">      <span class="attr">src</span>=<span class="string">&quot;https://example.com/web-apps/apps/api/documents/api.js&quot;</span></span></span><br><span class="line"><span class="tag">    &gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;preview&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span> <span class="attr">type</span>=<span class="string">&quot;module&quot;</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">let</span> config = &#123;</span></span><br><span class="line"><span class="language-javascript">        <span class="attr">document</span>: &#123;</span></span><br><span class="line"><span class="language-javascript">          <span class="attr">documentType</span>: <span class="string">&#x27;text&#x27;</span>,</span></span><br><span class="line"><span class="language-javascript">          <span class="attr">width</span>: <span class="string">&#x27;100%&#x27;</span>, <span class="comment">//打开窗口宽度</span></span></span><br><span class="line"><span class="language-javascript">          <span class="attr">height</span>: <span class="string">&#x27;100%&#x27;</span>, <span class="comment">//打开窗口高度</span></span></span><br><span class="line"><span class="language-javascript">          <span class="attr">fileType</span>: fileType, <span class="comment">//文档类型</span></span></span><br><span class="line"><span class="language-javascript">          <span class="attr">key</span>: key, <span class="comment">//定义用于服务识别文档的唯一文档标识符。每次编辑和保存文档时，都必须重新生成密钥。长度限制为128个符号。</span></span></span><br><span class="line"><span class="language-javascript">          <span class="attr">title</span>: title, <span class="comment">//为查看或编辑的文档定义所需的文件名，该文件名也将在下载文档时用作文件名。长度限制为128个符号。</span></span></span><br><span class="line"><span class="language-javascript">          <span class="attr">url</span>: url, <span class="comment">//定义存储原始查看或编辑的文档的绝对URL</span></span></span><br><span class="line"><span class="language-javascript">          <span class="attr">info</span>: &#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="attr">owner</span>: <span class="string">&#x27;&#x27;</span>, <span class="comment">//文件创建者名称</span></span></span><br><span class="line"><span class="language-javascript">            <span class="attr">sharingSettings</span>: [</span></span><br><span class="line"><span class="language-javascript">              <span class="comment">//文件对应用户的操作权限配置</span></span></span><br><span class="line"><span class="language-javascript">              &#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="attr">permissions</span>: <span class="string">&#x27;Full Access&#x27;</span>, <span class="comment">// 完全操作权限-Full Access,只读权限-Read Only 拒绝访问-Deny Access</span></span></span><br><span class="line"><span class="language-javascript">                <span class="attr">user</span>: <span class="string">&#x27;&#x27;</span>, <span class="comment">//有次权限的用户</span></span></span><br><span class="line"><span class="language-javascript">              &#125;,</span></span><br><span class="line"><span class="language-javascript">              &#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="attr">permissions</span>: <span class="string">&#x27;Read Only&#x27;</span>,</span></span><br><span class="line"><span class="language-javascript">                <span class="attr">user</span>: <span class="string">&#x27;&#x27;</span>,</span></span><br><span class="line"><span class="language-javascript">              &#125;,</span></span><br><span class="line"><span class="language-javascript">            ],</span></span><br><span class="line"><span class="language-javascript">            <span class="attr">uploaded</span>: <span class="string">&#x27;&#x27;</span>, <span class="comment">//文件创建时间</span></span></span><br><span class="line"><span class="language-javascript">          &#125;,</span></span><br><span class="line"><span class="language-javascript">          <span class="comment">//文档权限参数</span></span></span><br><span class="line"><span class="language-javascript">          <span class="attr">permissions</span>: &#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="attr">edit</span>: <span class="literal">true</span>, <span class="comment">//（文件是否可以编辑，false时文件不可编辑）</span></span></span><br><span class="line"><span class="language-javascript">            <span class="attr">fillForms</span>: <span class="literal">true</span>, <span class="comment">//定义是否能在文档中填充表单</span></span></span><br><span class="line"><span class="language-javascript">            <span class="attr">print</span>: <span class="literal">true</span>, <span class="comment">//定义文档是否能打印</span></span></span><br><span class="line"><span class="language-javascript">            <span class="attr">review</span>: <span class="literal">false</span>, <span class="comment">//第一是否显示审阅文档菜单</span></span></span><br><span class="line"><span class="language-javascript">            <span class="attr">comment</span>: <span class="literal">true</span>, <span class="comment">//定义是否可以注释文档。如果注释权限设置为“ true”，则文档侧栏将包含“注释”菜单选项；只有将mode参数设置为edit时才生效，默认值与edit参数的值一致。</span></span></span><br><span class="line"><span class="language-javascript">            <span class="attr">copy</span>: <span class="literal">true</span>, <span class="comment">//是否允许您将内容复制到剪贴板。默认值为true。</span></span></span><br><span class="line"><span class="language-javascript">            <span class="attr">download</span>: <span class="literal">true</span>, <span class="comment">//定义是否可以下载文档或仅在线查看或编辑文档。如果下载权限设置为“false”下载为菜单选项将没有。默认值为true。</span></span></span><br><span class="line"><span class="language-javascript">            <span class="attr">modifyContentControl</span>: <span class="literal">true</span>, <span class="comment">//定义是否可以更改内容控件设置。仅当mode参数设置为edit时，内容控件修改才可用于文档编辑器。默认值为true。</span></span></span><br><span class="line"><span class="language-javascript">            <span class="attr">modifyFilter</span>: <span class="literal">true</span>, <span class="comment">//定义过滤器是否可以全局应用（true）影响所有其他用户，或局部应用（false），即仅适用于当前用户。如果将mode参数设置为edit，则过滤器修改仅对电子表格编辑器可用。默认值为true。</span></span></span><br><span class="line"><span class="language-javascript">          &#125;,</span></span><br><span class="line"><span class="language-javascript">        &#125;,</span></span><br><span class="line"><span class="language-javascript">        <span class="comment">// type: &quot;embedded&quot;,</span></span></span><br><span class="line"><span class="language-javascript">        <span class="comment">//打开文档类型</span></span></span><br><span class="line"><span class="language-javascript">        <span class="comment">// text对应各种文档类型(.doc, .docm, .docx, .dot, .dotm, .dotx, .epub, .fodt, .htm, .html, .mht, .odt, .ott, .pdf, .rtf, .txt, .djvu, .xps)</span></span></span><br><span class="line"><span class="language-javascript">        <span class="comment">//spreadsheet对应表格类型(.csv, .fods, .ods, .ots, .xls, .xlsm, .xlsx, .xlt, .xltm, .xltx)</span></span></span><br><span class="line"><span class="language-javascript">        <span class="comment">//presentation对应PPT类型(.fodp, .odp, .otp, .pot, .potm, .potx, .pps, .ppsm, .ppsx, .ppt, .pptm, .pptx)</span></span></span><br><span class="line"><span class="language-javascript">        <span class="attr">editorConfig</span>: &#123;</span></span><br><span class="line"><span class="language-javascript">          <span class="comment">//编辑配置</span></span></span><br><span class="line"><span class="language-javascript">          <span class="attr">createUrl</span>: <span class="string">&#x27;http://docServer:port/url-to-create-document/&#x27;</span>, <span class="comment">//指定创建文件的页面,添加该配置后文档服务器插件才会显示新建文件按钮</span></span></span><br><span class="line"><span class="language-javascript">          <span class="attr">mode</span>: model, <span class="comment">//文档操作模式 view 视图模式不可编辑  edit 编辑模式可编辑文档</span></span></span><br><span class="line"><span class="language-javascript">          <span class="attr">callbackUrl</span>: callbackUrl, <span class="comment">//保存文件时的回调地址</span></span></span><br><span class="line"><span class="language-javascript">          <span class="attr">lang</span>: <span class="string">&#x27;zh-CN&#x27;</span>, <span class="comment">//语言环境</span></span></span><br><span class="line"><span class="language-javascript">          <span class="attr">customization</span>: &#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="comment">//定制部分允许自定义编辑器界面，使其看起来像您的其他产品，并更改是否存在其他按钮，链接，更改徽标和编辑者所有者详细信息。</span></span></span><br><span class="line"><span class="language-javascript">            <span class="attr">help</span>: <span class="literal">false</span>, <span class="comment">//定义是显示还是隐藏“帮助”菜单按钮。默认值为true。</span></span></span><br><span class="line"><span class="language-javascript">            <span class="attr">hideRightMenu</span>: <span class="literal">false</span>, <span class="comment">//定义在第一次加载时是显示还是隐藏右侧菜单。默认值为false。</span></span></span><br><span class="line"><span class="language-javascript">            <span class="attr">autosave</span>: <span class="literal">false</span>, <span class="comment">//定义是启用还是禁用“自动保存”菜单选项。请注意，如果您在菜单中更改此选项，它将被保存到浏览器的localStorage中。默认值为true。</span></span></span><br><span class="line"><span class="language-javascript">            <span class="attr">forcesave</span>: <span class="literal">true</span>, <span class="comment">//定义保存按钮是否显示默认false</span></span></span><br><span class="line"><span class="language-javascript">            <span class="attr">chat</span>: <span class="literal">false</span>, <span class="comment">//定义“聊天”菜单按钮是显示还是隐藏；请注意，如果您隐藏“聊天”按钮，则相应的聊天功能也将被禁用。默认值为true。</span></span></span><br><span class="line"><span class="language-javascript">            <span class="attr">commentAuthorOnly</span>: <span class="literal">false</span>, <span class="comment">//定义用户是否只能编辑和删除他的评论。默认值为false。</span></span></span><br><span class="line"><span class="language-javascript">            <span class="attr">comments</span>: <span class="literal">false</span>, <span class="comment">//定义是显示还是隐藏“注释”菜单按钮；请注意，如果您隐藏“评论”按钮，则相应的评论功能将仅可用于查看，评论的添加和编辑将不可用。默认值为true。</span></span></span><br><span class="line"><span class="language-javascript">            <span class="attr">compactHeader</span>: <span class="literal">false</span>, <span class="comment">//定义是否将菜单栏放在在徽标旁边使界面更加紧凑默认false。</span></span></span><br><span class="line"><span class="language-javascript">            <span class="attr">compactToolbar</span>: <span class="literal">false</span>, <span class="comment">//定义显示的顶部工具栏类型是完整（false）还是紧凑true。默认值为false 多余菜单将在右侧折叠点击显示。</span></span></span><br><span class="line"><span class="language-javascript">            <span class="attr">compatibleFeatures</span>: <span class="literal">false</span>, <span class="comment">//定义仅与OOXML格式兼容的功能的使用。例如，不要在整个文档上使用注释。默认值为false。</span></span></span><br><span class="line"><span class="language-javascript">            <span class="attr">macros</span>: <span class="literal">false</span>, <span class="comment">//定义是否将运行文档宏以及可用的宏设置。默认值为true。</span></span></span><br><span class="line"><span class="language-javascript">            <span class="attr">macrosMode</span>: <span class="string">&#x27;warn&#x27;</span>, <span class="comment">//定义是否将运行文档宏。可以采用以下值： disable -根本不运行；enable -自动运行所有宏；warn -警告宏并请求允许运行。默认值为original。</span></span></span><br><span class="line"><span class="language-javascript">            <span class="attr">plugins</span>: <span class="literal">false</span>, <span class="comment">//定义是否将启动插件并可用。默认值为true。</span></span></span><br><span class="line"><span class="language-javascript">            <span class="attr">showReviewChanges</span>: <span class="literal">false</span>, <span class="comment">//定义在加载编辑器时是否自动显示或隐藏审阅更改面板。默认值为false。</span></span></span><br><span class="line"><span class="language-javascript">            <span class="attr">spellcheck</span>: <span class="literal">false</span>, <span class="comment">//定义在加载编辑器时是否自动打开或关闭拼写检查器。拼写检查器仅适用于文档编辑器和演示文稿编辑器。默认值为true。</span></span></span><br><span class="line"><span class="language-javascript">            <span class="attr">toolbarNoTabs</span>: <span class="literal">false</span>, <span class="comment">//定义是突出显示顶部工具栏选项卡样式。默认值为false。</span></span></span><br><span class="line"><span class="language-javascript">            <span class="attr">unit</span>: <span class="string">&#x27;cm&#x27;</span>, <span class="comment">//定义在标尺和对话框中使用的度量单位。可以采用以下值：cm -厘米，pt-点，inch -英寸。默认值为厘米（cm）。</span></span></span><br><span class="line"><span class="language-javascript">            <span class="attr">zoom</span>: <span class="number">100</span>, <span class="comment">//定义以百分比为单位的文档显示缩放值。可以取大于0的值。对于文本文档和演示文稿，可以将此参数设置为-1（使文档适合页面选项）或-2（使文档页面宽度适合编辑器页面）。默认值为100。</span></span></span><br><span class="line"><span class="language-javascript">            <span class="attr">customer</span>: &#123;</span></span><br><span class="line"><span class="language-javascript">              <span class="comment">//关于 文档编辑器的显示信息</span></span></span><br><span class="line"><span class="language-javascript">              <span class="attr">address</span>: <span class="string">&#x27;My City, 123a-45&#x27;</span>, <span class="comment">//有权访问编辑或编辑作者的公司或个人的邮政地址，</span></span></span><br><span class="line"><span class="language-javascript">              <span class="attr">info</span>: <span class="string">&#x27;Some additional information&#x27;</span>, <span class="comment">//有关您希望其他人认识的公司或个人的一些其他信息，</span></span></span><br><span class="line"><span class="language-javascript">              <span class="attr">logo</span>: <span class="string">&#x27;https://example.com/logo-big.png&#x27;</span>, <span class="comment">//图片徽标的路径（此文件没有特别建议，但是如果使用透明背景的.png格式会更好）。图片必须具有以下尺寸：432x70，</span></span></span><br><span class="line"><span class="language-javascript">              <span class="attr">mail</span>: <span class="string">&#x27;john@example.com&#x27;</span>, <span class="comment">//有权访问编辑者或编辑者的公司或个人的电子邮件地址</span></span></span><br><span class="line"><span class="language-javascript">              <span class="attr">name</span>: <span class="string">&#x27;欧阳锋&#x27;</span>, <span class="comment">//该公司或个人的谁可以访问编辑或编辑作者，名称</span></span></span><br><span class="line"><span class="language-javascript">              <span class="attr">www</span>: <span class="string">&#x27;example.com&#x27;</span>, <span class="comment">//以上公司或个人的家庭网站地址，</span></span></span><br><span class="line"><span class="language-javascript">            &#125;,</span></span><br><span class="line"><span class="language-javascript">            <span class="attr">feedback</span>: &#123;</span></span><br><span class="line"><span class="language-javascript">              <span class="comment">//反馈配置信息</span></span></span><br><span class="line"><span class="language-javascript">              <span class="attr">url</span>: <span class="string">&#x27;https://example.com&#x27;</span>, <span class="comment">//单击“反馈和支持”菜单按钮时将打开的网站地址的绝对URL ，</span></span></span><br><span class="line"><span class="language-javascript">              <span class="attr">visible</span>: <span class="literal">false</span>, <span class="comment">//显示或隐藏“反馈和支持”菜单按钮，</span></span></span><br><span class="line"><span class="language-javascript">            &#125;,</span></span><br><span class="line"><span class="language-javascript">            <span class="attr">goback</span>: &#123;</span></span><br><span class="line"><span class="language-javascript">              <span class="comment">//定义“打开文件位置”菜单按钮和右上角按钮的设置。该对象具有以下参数：</span></span></span><br><span class="line"><span class="language-javascript">              <span class="attr">blank</span>: <span class="literal">true</span>, <span class="comment">//在新的浏览器选项卡/窗口（如果值设置为true）或当前选项卡（如果值设置为false）中打开网站。默认值为true，</span></span></span><br><span class="line"><span class="language-javascript">              <span class="attr">requestClose</span>: <span class="literal">false</span>, <span class="comment">//定义如果单击“打开文件位置”按钮，则调用events.onRequestClose事件，而不是打开浏览器选项卡或窗口。默认值为false，</span></span></span><br><span class="line"><span class="language-javascript">              <span class="attr">text</span>: <span class="string">&#x27;Open file location&#x27;</span>, <span class="comment">//将在“打开文件位置”菜单按钮和右上角按钮（即，而不是“转到文档”）上显示的文本，</span></span></span><br><span class="line"><span class="language-javascript">              <span class="attr">url</span>: <span class="string">&#x27;https://example.com&#x27;</span>, <span class="comment">//单击“打开文件位置”菜单按钮时将打开的网站地址的绝对URL ，</span></span></span><br><span class="line"><span class="language-javascript">            &#125;,</span></span><br><span class="line"><span class="language-javascript">            <span class="attr">logo</span>: &#123;</span></span><br><span class="line"><span class="language-javascript">              <span class="attr">image</span>: <span class="string">&#x27;https://example.com/logo.png&#x27;</span>, <span class="comment">//图像文件的路径，用于在普通工作模式下显示（即，在所有编辑器的查看和编辑模式下）。图片必须具有以下尺寸：172x40，</span></span></span><br><span class="line"><span class="language-javascript">              <span class="attr">imageEmbedded</span>: <span class="string">&#x27;https://example.com/logo_em.png&#x27;</span>, <span class="comment">//用于以嵌入式模式显示的图像文件的路径（请参阅config部分以了解如何定义嵌入式文档类型）。图片必须具有以下尺寸：248x40，</span></span></span><br><span class="line"><span class="language-javascript">              <span class="attr">url</span>: <span class="string">&#x27;https://www.baidu.com&#x27;</span>, <span class="comment">//某人单击徽标图像时将使用的绝对URL（可用于转到您的网站等）。保留为空字符串或null以使徽标不可单击，</span></span></span><br><span class="line"><span class="language-javascript">            &#125;,</span></span><br><span class="line"><span class="language-javascript">          &#125;,</span></span><br><span class="line"><span class="language-javascript">          <span class="attr">user</span>: &#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="comment">//用户信息</span></span></span><br><span class="line"><span class="language-javascript">            <span class="attr">id</span>: <span class="string">&#x27;admin&#x27;</span>, <span class="comment">//用户ID</span></span></span><br><span class="line"><span class="language-javascript">            <span class="attr">name</span>: <span class="string">&#x27;操作员&#x27;</span>, <span class="comment">//用户全名称</span></span></span><br><span class="line"><span class="language-javascript">          &#125;,</span></span><br><span class="line"><span class="language-javascript">          <span class="attr">embedded</span>: &#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="comment">//Embedded部分仅适用于嵌入式文档类型（请参阅config部分以了解如何定义嵌入式文档类型）。它允许更改设置，这些设置定义嵌入式模式下按钮的行为。</span></span></span><br><span class="line"><span class="language-javascript">            <span class="attr">embedUrl</span>: <span class="string">&#x27;https://example.com/embedded?doc=exampledocument1.docx&#x27;</span>, <span class="comment">//定义文档的绝对URL，以作为嵌入到网页中的文档的源文件</span></span></span><br><span class="line"><span class="language-javascript">            <span class="attr">fullscreenUrl</span>: <span class="string">&#x27;https://example.com/embedded?doc=exampledocument1.docx#fullscreen&#x27;</span>, <span class="comment">//定义将以全屏模式打开的文档的绝对URL。</span></span></span><br><span class="line"><span class="language-javascript">            <span class="attr">saveUrl</span>: <span class="string">&#x27;https://example.com/download?doc=exampledocument1.docx&#x27;</span>, <span class="comment">//定义允许将文档保存到用户个人计算机上的绝对URL。</span></span></span><br><span class="line"><span class="language-javascript">            <span class="attr">shareUrl</span>: <span class="string">&#x27;https://example.com/view?doc=exampledocument1.docx&#x27;</span>, <span class="comment">//定义允许其他用户共享此文档的绝对URL。</span></span></span><br><span class="line"><span class="language-javascript">            <span class="attr">toolbarDocked</span>: <span class="string">&#x27;top&#x27;</span>, <span class="comment">//定义嵌入式查看器工具栏的位置，可以为top或bottom。</span></span></span><br><span class="line"><span class="language-javascript">          &#125;,</span></span><br><span class="line"><span class="language-javascript">        &#125;,</span></span><br><span class="line"><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">        <span class="attr">events</span>: &#123;</span></span><br><span class="line"><span class="language-javascript">          <span class="comment">//事件配置</span></span></span><br><span class="line"><span class="language-javascript">          <span class="comment">// onAppReady,//-将应用程序加载到浏览器时调用的函数。</span></span></span><br><span class="line"><span class="language-javascript">          <span class="comment">// onCollaborativeChanges //-当文档由其他用户在严格共同编辑模式下共同编辑时调用的函数。</span></span></span><br><span class="line"><span class="language-javascript">          <span class="comment">// onDocumentReady,//-将应用程序加载到浏览器时调用的函数。</span></span></span><br><span class="line"><span class="language-javascript">          <span class="comment">// onDocumentStateChange,//-修改文档时调用的函数。这就是所谓的使用参数：&#123;真正的“数据”&#125;在当前用户编辑文档以及与参数：&#123;“数据”：假&#125;在当前用户的更改发送到文档编辑服务。</span></span></span><br><span class="line"><span class="language-javascript">          <span class="comment">// onDownloadAs,//-调用downloadAs方法时，使用指向已编辑文件的绝对URL调用的函数。在data参数中发送要下载的文档的绝对URL 。</span></span></span><br><span class="line"><span class="language-javascript">          <span class="comment">// onError,//-发生错误或其他特定事件时调用的函数。错误消息在data参数中发送。==</span></span></span><br><span class="line"><span class="language-javascript">          <span class="comment">// onInfo,//-应用程序打开文件时调用的函数。该模式在data.mode参数中发送。可以查看或编辑。</span></span></span><br><span class="line"><span class="language-javascript">          <span class="comment">// onMetaChange,//-通过meta命令更改文档的元信息时调用的函数。文档名称通过data.title参数发送。</span></span></span><br><span class="line"><span class="language-javascript">          <span class="comment">// onOutdatedVersion,//-使用旧的document.key值打开文档进行编辑时，显示错误后调用的函数，该值用于编辑先前的文档版本并已成功保存。调用此事件时，必须使用新的document.key重新初始化编辑器。</span></span></span><br><span class="line"><span class="language-javascript">          <span class="comment">// onReady,//-将应用程序加载到浏览器时调用的函数。自从5.0版本不推荐使用，请使用onAppReady代替</span></span></span><br><span class="line"><span class="language-javascript">          <span class="comment">// onRequestClose,//-结束编辑器的工作并且必须关闭编辑器时调用的函数。==</span></span></span><br><span class="line"><span class="language-javascript">          <span class="comment">// onRequestCompareFile,//-用户尝试通过单击“存储中的文档”按钮来选择要比较的文档时调用的函数。要选择要比较的文档，必须调用setRevisedFile方法。如果未声明该方法，则不会显示“来自存储的文档”按钮。</span></span></span><br><span class="line"><span class="language-javascript">          <span class="comment">// onRequestCreateNew,//-用户尝试通过单击“新建”按钮来创建文档时调用的函数。使用此方法代替createUrl字段。如果未声明该方法且未指定createUrl，则将不会显示“创建新”按钮。</span></span></span><br><span class="line"><span class="language-javascript">          <span class="comment">// onRequestEditRights,//-用户尝试通过单击“编辑文档”按钮尝试将文档从视图切换到编辑模式时调用的函数。调用该函数时，必须在编辑模式下再次初始化编辑器。如果未声明该方法，则不会显示“编辑”按钮。</span></span></span><br><span class="line"><span class="language-javascript">          <span class="comment">// onRequestHistory,//-用户尝试通过单击“版本历史记录”按钮显示文档版本历史记录时调用的函数。要显示文档版本历史，您必须调用refreshHistory方法。如果未声明该方法和onRequestHistoryData方法，则不会显示“版本历史记录”按钮。</span></span></span><br><span class="line"><span class="language-javascript">          <span class="comment">// onRequestHistoryClose,//-当用户尝试通过单击“关闭历史记录”按钮来查看文档版本历史记录时，试图调用该文档时调用的函数。调用该函数时，必须在编辑模式下再次初始化编辑器。如果未声明该方法，则不会显示“关闭历史记录”按钮。</span></span></span><br><span class="line"><span class="language-javascript">          <span class="comment">// onRequestHistoryData,//-用户尝试单击文档版本历史记录中的特定文档版本时调用的函数。</span></span></span><br><span class="line"><span class="language-javascript">          <span class="comment">// onRequestInsertImage,//-用户尝试通过单击“保存图像”按钮插入图像时调用的函数。图像插入的类型在参数data.c中指定。</span></span></span><br><span class="line"><span class="language-javascript">          <span class="comment">// onRequestRename,//-用户尝试通过单击“重命名...”按钮重命名文件时调用的函数。</span></span></span><br><span class="line"><span class="language-javascript">          <span class="comment">// onRequestRestore,//-用户单击版本历史记录中的“还原”按钮来还原文件版本时调用的函数。</span></span></span><br><span class="line"><span class="language-javascript">          <span class="comment">// onRequestSaveAs,//-用户尝试通过单击“另存为...”按钮保存文件时调用的函数。文档的标题和要下载的文档的绝对URL在data参数中发送。如果未声明该方法，则不会显示“另存为...”按钮。</span></span></span><br><span class="line"><span class="language-javascript">          <span class="comment">// onRequestSharingSettings,//-用户单击“更改访问权限”按钮来管理文档访问权限时调用的函数。必须调用setSharingSettings方法来更新有关允许与其他用户共享文档的设置的信息。如果未声明该方法，则不会显示“更改访问权限”按钮。</span></span></span><br><span class="line"><span class="language-javascript">          <span class="comment">// onRequestUsers,//-评论者可以选择要在评论中提及的其他用户时调用的函数。要设置用户列表，必须调用setUsers方法。</span></span></span><br><span class="line"><span class="language-javascript">          <span class="comment">// onWarning,//-发生警告时调用的函数。警告消息在data参数中发送。</span></span></span><br><span class="line"><span class="language-javascript">          <span class="comment">// &quot;onDocumentStateChange&quot;: function() &#123;</span></span></span><br><span class="line"><span class="language-javascript">          <span class="comment">// &#125;, //文档改变后的回调</span></span></span><br><span class="line"><span class="language-javascript">          <span class="comment">//&quot;onDocumentReady&quot; : onDocumentReady, //文档初始化准备好后的回调</span></span></span><br><span class="line"><span class="language-javascript">        &#125;,</span></span><br><span class="line"><span class="language-javascript">      &#125;</span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">const</span> docEditor = <span class="keyword">new</span> <span class="title class_">DocsAPI</span>.<span class="title class_">DocEditor</span>(<span class="string">&#x27;preview&#x27;</span>, config)</span></span><br><span class="line"><span class="language-javascript">    </span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure>]]>
    </content>
    <id>https://blog.zhangsifan.com/posts/20251011oo/</id>
    <link href="https://blog.zhangsifan.com/posts/20251011oo/"/>
    <published>2025-10-10T16:00:00.000Z</published>
    <summary>ONLYOFFICE 是一个开源办公软件项目，专注于先进且安全的办公解决方案。ONLYOFFICE 在全球拥有超过 1500 万用户，并在在线办公领域以其创新而闻名。ONLYOFFICE 生态包括协作应用程序，如在线文本文档、电子表格、演示文稿、表单和 PDF 编辑器，以及基于房间的协作平台。作为一个国际公司，ONLYOFFICE 在全球范围内都有员工和贡献者，办公室分布于新加坡、里加、伦敦、贝尔格莱德、埃里温、塔什干和上海。</summary>
    <title>OnlyOffice 前端使用教程</title>
    <updated>2026-03-31T03:22:20.637Z</updated>
  </entry>
  <entry>
    <author>
      <name>JCAlways</name>
    </author>
    <category term="我的世界" scheme="https://blog.zhangsifan.com/categories/%E6%88%91%E7%9A%84%E4%B8%96%E7%95%8C/"/>
    <category term="我的世界" scheme="https://blog.zhangsifan.com/tags/%E6%88%91%E7%9A%84%E4%B8%96%E7%95%8C/"/>
    <content>
      <![CDATA[<p>在Switch版本中，任天堂出于安全因素考虑，屏蔽了使用IP地址连接自建服务器的功能，对Switch端的游玩造成了较大的不便。</p><p>本文使用了基于<code>小米路由器自定义Hosts</code>的原理，通过将Switch版本中的默认联机服务器的IP地址劫持为目标服务器，实现了Switch版连接自建云服务器的功能。</p><h1 id="修改路由器Hosts"><a href="#修改路由器Hosts" class="headerlink" title="修改路由器Hosts"></a>修改路由器Hosts</h1><figure class="highlight text"><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></pre></td><td class="code"><pre><span class="line">192.168.1.88 hivebedrock.network</span><br><span class="line">192.168.1.88 mco.mineplex.com</span><br><span class="line">192.168.1.88 play.inpvp.net</span><br><span class="line">192.168.1.88 mco.lbsg.net</span><br><span class="line">192.168.1.88 mco.cubecraft.net</span><br></pre></td></tr></table></figure>]]>
    </content>
    <id>https://blog.zhangsifan.com/posts/20250925mc/</id>
    <link href="https://blog.zhangsifan.com/posts/20250925mc/"/>
    <published>2025-09-24T16:00:00.000Z</published>
    <summary>Nintendo Switch 我的世界 连接第三方服务器</summary>
    <title>Nintendo Switch 我的世界 连接第三方服务器</title>
    <updated>2026-03-31T03:22:20.637Z</updated>
  </entry>
  <entry>
    <author>
      <name>JCAlways</name>
    </author>
    <content>
      <![CDATA[<p><a href="https://www.npmjs.com/package/nprogress">官方文档</a></p><h1 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h1><h2 id="使用-宝塔面板-Docker-安装"><a href="#使用-宝塔面板-Docker-安装" class="headerlink" title="使用 宝塔面板 Docker 安装"></a>使用 宝塔面板 Docker 安装</h2><p><img src="https://s2.loli.net/2025/09/05/eBzhS35rQpbatUl.png" alt="gitlab安装配置"></p><h2 id="完整docker-compose-yml"><a href="#完整docker-compose-yml" class="headerlink" title="完整docker-compose.yml"></a>完整docker-compose.yml</h2><figure class="highlight yaml"><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></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="attr">services:</span></span><br><span class="line">  <span class="attr">gitlab:</span></span><br><span class="line">    <span class="attr">image:</span> <span class="string">gitlab/gitlab-ce:$&#123;VERSION&#125;</span></span><br><span class="line">    <span class="comment">#    container_name: $&#123;CONTAINER_NAME&#125;</span></span><br><span class="line">    <span class="attr">deploy:</span></span><br><span class="line">      <span class="attr">resources:</span></span><br><span class="line">        <span class="attr">limits:</span></span><br><span class="line">          <span class="attr">cpus:</span> <span class="string">$&#123;CPUS&#125;</span></span><br><span class="line">          <span class="attr">memory:</span> <span class="string">$&#123;MEMORY_LIMIT&#125;</span></span><br><span class="line">    <span class="attr">restart:</span> <span class="string">always</span></span><br><span class="line">    <span class="attr">hostname:</span> <span class="string">$&#123;DOMAIN_HOST&#125;</span></span><br><span class="line">    <span class="attr">shm_size:</span> <span class="string">&#x27;256m&#x27;</span></span><br><span class="line">    <span class="attr">ports:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">$&#123;HOST_IP&#125;:$&#123;WEB_HTTP_PORT&#125;:80</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">$&#123;HOST_IP&#125;:$&#123;WEB_HTTPS_PORT&#125;:443</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">$&#123;HOST_IP&#125;:$&#123;WEB_SSH_PORT&#125;:22</span></span><br><span class="line">    <span class="attr">environment:</span></span><br><span class="line">      <span class="attr">GITLAB_OMNIBUS_CONFIG:</span> <span class="string">|</span></span><br><span class="line"><span class="string">        # Add any other gitlab.rb configuration here, each on its own line</span></span><br><span class="line"><span class="string">        external_url &#x27;https://$&#123;DOMAIN_HOST&#125;&#x27;</span></span><br><span class="line"><span class="string">        nginx[&#x27;listen_port&#x27;] = 80</span></span><br><span class="line"><span class="string">        nginx[&#x27;listen_https&#x27;] = false</span></span><br><span class="line"><span class="string">        nginx[&#x27;proxy_set_headers&#x27;] = &#123; &quot;X-Forwarded-Proto&quot; =&gt; &quot;https&quot;, &quot;X-Forwarded-Ssl&quot; =&gt; &quot;on&quot; &#125;</span></span><br><span class="line"><span class="string">        nginx[&#x27;client_max_body_size&#x27;] = &#x27;0&#x27;</span></span><br><span class="line"><span class="string">        nginx[&#x27;proxy_read_timeout&#x27;] = 600</span></span><br><span class="line"><span class="string">        nginx[&#x27;proxy_connect_timeout&#x27;] = 600</span></span><br><span class="line"><span class="string">        nginx[&#x27;proxy_send_timeout&#x27;] = 600</span></span><br><span class="line"><span class="string">        nginx[&#x27;gzip_enabled&#x27;] = false</span></span><br><span class="line"><span class="string">        gitlab_rails[&#x27;smtp_enable&#x27;] = true</span></span><br><span class="line"><span class="string">        gitlab_rails[&#x27;smtp_address&#x27;] = &quot;smtp.ym.163.com&quot;</span></span><br><span class="line"><span class="string">        gitlab_rails[&#x27;smtp_port&#x27;] = 465</span></span><br><span class="line"><span class="string">        gitlab_rails[&#x27;smtp_user_name&#x27;] = &quot;robot@domain.com&quot;</span></span><br><span class="line"><span class="string">        gitlab_rails[&#x27;smtp_password&#x27;] = &quot;PASSWORD&quot;</span></span><br><span class="line"><span class="string">        gitlab_rails[&#x27;smtp_domain&#x27;] = &quot;smtp.ym.163.com&quot;</span></span><br><span class="line"><span class="string">        gitlab_rails[&#x27;smtp_authentication&#x27;] = &quot;login&quot;</span></span><br><span class="line"><span class="string">        gitlab_rails[&#x27;smtp_enable_starttls_auto&#x27;] = false</span></span><br><span class="line"><span class="string">        gitlab_rails[&#x27;smtp_tls&#x27;] = true</span></span><br><span class="line"><span class="string">        gitlab_rails[&#x27;gitlab_email_from&#x27;] = &#x27;robot@domain.com&#x27;</span></span><br><span class="line"><span class="string"></span>    <span class="attr">volumes:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">$&#123;APP_PATH&#125;/config:/etc/gitlab</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">$&#123;APP_PATH&#125;/logs:/var/log/gitlab</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">$&#123;APP_PATH&#125;/data:/var/opt/gitlab</span></span><br><span class="line">    <span class="attr">labels:</span></span><br><span class="line">      <span class="attr">createdBy:</span> <span class="string">&quot;bt_apps&quot;</span></span><br><span class="line">    <span class="attr">networks:</span></span><br><span class="line">      <span class="bullet">-</span> <span class="string">baota_net</span></span><br><span class="line"></span><br><span class="line"><span class="attr">networks:</span></span><br><span class="line">  <span class="attr">baota_net:</span></span><br><span class="line">    <span class="attr">external:</span> <span class="literal">true</span></span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="完整-env"><a href="#完整-env" class="headerlink" title="完整.env"></a>完整.env</h2><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">VERSION=latest</span><br><span class="line">CONTAINER_NAME=CONTAINER_NAME</span><br><span class="line">HOST_IP=127.0.0.1</span><br><span class="line">WEB_HTTP_PORT=10080</span><br><span class="line">WEB_HTTPS_PORT=10443</span><br><span class="line">WEB_SSH_PORT=10022</span><br><span class="line">DOMAIN_HOST=git.domain.com</span><br><span class="line">CPUS=0</span><br><span class="line">MEMORY_LIMIT=0MB</span><br><span class="line">APP_PATH=/www/dk_project/dk_app/gitlab/gitlab</span><br></pre></td></tr></table></figure><h1 id="邮件服务配置"><a href="#邮件服务配置" class="headerlink" title="邮件服务配置"></a>邮件服务配置</h1><p><a href="https://docs.gitlab.com/omnibus/settings/smtp/">官方文档</a></p><p>在docker-compose.yml 中GITLAB_OMNIBUS_CONFIG 修改</p><h2 id="网易免费企业邮箱"><a href="#网易免费企业邮箱" class="headerlink" title="网易免费企业邮箱"></a>网易免费企业邮箱</h2><figure class="highlight ruby"><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></pre></td><td class="code"><pre><span class="line">gitlab_rails[<span class="string">&#x27;smtp_enable&#x27;</span>] = <span class="literal">true</span></span><br><span class="line">gitlab_rails[<span class="string">&#x27;smtp_address&#x27;</span>] = <span class="string">&quot;smtp.ym.163.com&quot;</span></span><br><span class="line">gitlab_rails[<span class="string">&#x27;smtp_port&#x27;</span>] = <span class="number">465</span></span><br><span class="line">gitlab_rails[<span class="string">&#x27;smtp_user_name&#x27;</span>] = <span class="string">&quot;xxxx@xx.com&quot;</span></span><br><span class="line">gitlab_rails[<span class="string">&#x27;smtp_password&#x27;</span>] = <span class="string">&quot;password&quot;</span></span><br><span class="line">gitlab_rails[<span class="string">&#x27;smtp_authentication&#x27;</span>] = <span class="string">&quot;login&quot;</span></span><br><span class="line">gitlab_rails[<span class="string">&#x27;smtp_enable_starttls_auto&#x27;</span>] = <span class="literal">false</span></span><br><span class="line">gitlab_rails[<span class="string">&#x27;smtp_tls&#x27;</span>] = <span class="literal">true</span></span><br><span class="line">gitlab_rails[<span class="string">&#x27;gitlab_email_from&#x27;</span>] = <span class="string">&#x27;xxxx@xx.com&#x27;</span></span><br><span class="line">gitlab_rails[<span class="string">&#x27;smtp_domain&#x27;</span>] = <span class="string">&quot;smtp.ym.163.com&quot;</span></span><br></pre></td></tr></table></figure><h2 id="测试-SMTP-配置"><a href="#测试-SMTP-配置" class="headerlink" title="测试 SMTP 配置"></a>测试 SMTP 配置</h2><p>您可以使用 Rails 控制台验证 GitLab 是否能够正常发送电子邮件。在 GitLab 服务器上，执行<code>gitlab-rails console</code>进入控制台。然后，您可以在控制台提示符下输入以下命令，让 GitLab 发送一封测试电子邮件：</p><figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="title class_">Notify</span>.test_email(<span class="string">&#x27;destination_email@address.com&#x27;</span>, <span class="string">&#x27;Message Subject&#x27;</span>, <span class="string">&#x27;Message Body&#x27;</span>).deliver_now</span><br></pre></td></tr></table></figure>]]>
    </content>
    <id>https://blog.zhangsifan.com/posts/20250905gl/</id>
    <link href="https://blog.zhangsifan.com/posts/20250905gl/"/>
    <published>2025-09-03T16:00:00.000Z</published>
    <summary>使用宝塔面板 Docker 安装 Gitlab CE 服务器</summary>
    <title>搭建 Gitlab CE 服务器</title>
    <updated>2026-03-31T03:22:20.637Z</updated>
  </entry>
  <entry>
    <author>
      <name>JCAlways</name>
    </author>
    <category term="OBS" scheme="https://blog.zhangsifan.com/categories/OBS/"/>
    <category term="OBS RTMP 服务器" scheme="https://blog.zhangsifan.com/tags/OBS-RTMP-%E6%9C%8D%E5%8A%A1%E5%99%A8/"/>
    <content>
      <![CDATA[<p><a href="https://github.com/superconvert/smart_rtmpd?tab=readme-ov-file">官方网站</a></p><h1 id="下载-服务端软件"><a href="#下载-服务端软件" class="headerlink" title="下载 服务端软件"></a>下载 服务端软件</h1><blockquote><p>下载 <code>rtmpd.zip</code> 文件</p></blockquote><p><a href="https://github.com/superconvert/smart_rtmpd/releases">rtmpd.zip</a></p><h2 id="解压运行"><a href="#解压运行" class="headerlink" title="解压运行"></a>解压运行</h2><ul><li>解压 <code>rtmpd.zip</code> 文件<ul><li>然后解压 <code>smart_rtmpd_win.zip</code> 文件夹</li><li>运行 <code>smart_rtmpd.exe</code> 重新</li><li>点击 启动 即可</li></ul></li></ul>]]>
    </content>
    <id>https://blog.zhangsifan.com/posts/20250707mp/</id>
    <link href="https://blog.zhangsifan.com/posts/20250707mp/"/>
    <published>2025-07-06T16:00:00.000Z</published>
    <summary>搭建 RTMP 推流服务器</summary>
    <title>搭建 RTMP 推流服务</title>
    <updated>2026-03-31T03:22:20.637Z</updated>
  </entry>
  <entry>
    <author>
      <name>JCAlways</name>
    </author>
    <category term="OBS" scheme="https://blog.zhangsifan.com/categories/OBS/"/>
    <category term="OBS 插件" scheme="https://blog.zhangsifan.com/tags/OBS-%E6%8F%92%E4%BB%B6/"/>
    <content>
      <![CDATA[<p><a href="https://sorayuki.github.io/obs-multi-rtmp/">官方网站</a></p><h1 id="OBS-Studio-下载"><a href="#OBS-Studio-下载" class="headerlink" title="OBS Studio 下载"></a>OBS Studio 下载</h1><p><a href="https://obsproject.com/download">Download | OBS</a></p><h1 id="OBS-多流推送插件下载"><a href="#OBS-多流推送插件下载" class="headerlink" title="OBS 多流推送插件下载"></a>OBS 多流推送插件下载</h1><p><a href="https://github.com/sorayuki/obs-multi-rtmp/releases">下载地址</a></p><h2 id="Windows-安装方式"><a href="#Windows-安装方式" class="headerlink" title="Windows 安装方式"></a>Windows 安装方式</h2><h3 id="下载插件"><a href="#下载插件" class="headerlink" title="下载插件"></a>下载插件</h3><p>下载 <code>obs-multi-rtmp-x.x.x.x-windows-x64.zip</code> 文件</p><h3 id="解压安装插件"><a href="#解压安装插件" class="headerlink" title="解压安装插件"></a>解压安装插件</h3><p>将 <code>data</code> 中的文件放到 OBS 安装目录的 <code>data</code> 文件夹中<br>将 <code>obs-plugins</code> 中的文件放到 OBS 安装目录的 <code>obs-plugins</code> 文件夹中</p><h2 id="Mac-OS-安装方式"><a href="#Mac-OS-安装方式" class="headerlink" title="Mac OS 安装方式"></a>Mac OS 安装方式</h2><h3 id="下载插件-1"><a href="#下载插件-1" class="headerlink" title="下载插件"></a>下载插件</h3><p>下载 <code>obs-multi-rtmp-x.x.x.x-macos-universal.pkg</code> 文件</p><h3 id="安装插件"><a href="#安装插件" class="headerlink" title="安装插件"></a>安装插件</h3><p>双击下载的文件安装即可 </p><h2 id="使用插件"><a href="#使用插件" class="headerlink" title="使用插件"></a>使用插件</h2><p>重新启动 OBS Studio 即可在 停靠窗口 -&gt; 多路推流 使用</p><h1 id="示例"><a href="#示例" class="headerlink" title="示例"></a>示例</h1><iframe src='https://sorayuki.github.io/obs-multi-rtmp/' style="width:100%;height:1000px;" frameborder="0"></iframe>]]>
    </content>
    <id>https://blog.zhangsifan.com/posts/20250707zb/</id>
    <link href="https://blog.zhangsifan.com/posts/20250707zb/"/>
    <published>2025-07-06T16:00:00.000Z</published>
    <summary>OBS多站点并发插件</summary>
    <title>OBS 多流推送</title>
    <updated>2026-03-31T03:22:20.637Z</updated>
  </entry>
  <entry>
    <author>
      <name>JCAlways</name>
    </author>
    <category term="我的世界" scheme="https://blog.zhangsifan.com/categories/%E6%88%91%E7%9A%84%E4%B8%96%E7%95%8C/"/>
    <category term="我的世界" scheme="https://blog.zhangsifan.com/tags/%E6%88%91%E7%9A%84%E4%B8%96%E7%95%8C/"/>
    <content>
      <![CDATA[<h1 id="下载服务器文件"><a href="#下载服务器文件" class="headerlink" title="下载服务器文件"></a>下载服务器文件</h1><ul><li>服务器系统 Ubuntu 22+</li><li>我们建议在至少具有 2 个内核和 1 Gb RAM 的 64 位 Intel 或 AMD 处理器机器上运行 Bedrock Minecraft 服务器。</li></ul><p>点击<a href="https://www.minecraft.net/en-us/download/server/bedrock">下载基岩版服务器文件</a></p><p>下载后上传至服务器 并解压文件</p><h1 id="宝塔服务器设置"><a href="#宝塔服务器设置" class="headerlink" title="宝塔服务器设置"></a>宝塔服务器设置</h1><p><img src="https://s2.loli.net/2025/04/24/byhiHTmlskXB2AN.png" alt="宝塔面板设置页面"></p><h1 id="服务器防火墙"><a href="#服务器防火墙" class="headerlink" title="服务器防火墙"></a>服务器防火墙</h1><h2 id="阿里云服务器防火墙设置"><a href="#阿里云服务器防火墙设置" class="headerlink" title="阿里云服务器防火墙设置"></a>阿里云服务器防火墙设置</h2><blockquote><p>记得 协议类型 选择全部流量!!!</p></blockquote><p><img src="https://s2.loli.net/2025/04/24/DTYAGhSljMirq3u.png" alt="阿里云防火墙设置.png"></p><h1 id="配置"><a href="#配置" class="headerlink" title="配置"></a>配置</h1><p>服务器将尝试读取名为 <code>server.properties</code> 的文件。其中一些选项仅在创建新世界时读取，而另一些选项则在每次启动时读取。该文件应包含一个列表，其中的键和值以等号分隔，每行一个。</p><p>有以下选项可用。如果值是括号中的数字，则可以使用该数字代替文本值。</p><table><thead><tr><th>Option name</th><th>Possible values</th><th>Default value</th><th>When is it used</th><th>Notes</th></tr></thead><tbody><tr><td>server-name</td><td>Any string (no semicolon allowed)</td><td>Dedicated Server</td><td>Always</td><td>这是游戏内服务器列表中显示的服务器名称。list.</td></tr><tr><td>gamemode</td><td>survival, creative, adventure</td><td>survival</td><td>Always or only for new players</td><td></td></tr><tr><td>force-gamemode</td><td>true, false</td><td>false</td><td>Always</td><td><strong>force-gamemode&#x3D;false</strong>（或 server.properties 文件中<strong>未定义 force-gamemode</strong>）可防止服务器向客户端发送除服务器在世界创建期间保存的 gamemode 值之外的 gamemodes 值，即使这些值是在世界创建后在 server.propertie 文件中设置的。force gamemode&#x3D;true强制服务器向客户端发送gamemode值，而不是服务器在世界创建期间保存的gamemode值（如果这些值在世界创建后在server.properties文件中设置）。</td></tr><tr><td>difficulty</td><td>peaceful, easy, normal, hard</td><td>easy</td><td>Always</td><td></td></tr><tr><td>allow-cheats</td><td>true, false</td><td>false</td><td>Always</td><td>如果为<strong>true</strong>，则可以使用命令等作弊手段。</td></tr><tr><td>max-players</td><td>Any integer</td><td>10</td><td>Always</td><td>The maximum numbers of players that should be able to play on the server. <strong>Higher values have performance impact.</strong></td></tr><tr><td>server-port</td><td>Integer between 1024 and 65535</td><td>19132</td><td>Always</td><td>可以使用低于1024的值，但通常保留用于众所周知的应用</td></tr><tr><td>server-portv6</td><td>Integer between 1024 and 65535</td><td>19133</td><td>Always</td><td>可以使用低于1024的值，但通常保留用于众所周知的应用</td></tr><tr><td>enable-lan-visibility</td><td>true, false</td><td>true</td><td>Always</td><td>倾听并回应在局域网上寻找服务器的客户端。这将导致服务器绑定到默认端口（19132、19133），即使“服务器端口”和“server-portv6”具有非默认值。如果不需要LAN发现，或者在同一主机上运行多个服务器可能导致端口冲突，请考虑关闭此功能。</td></tr><tr><td>level-name</td><td>Any string</td><td>Bedrock level</td><td>Always</td><td>The name of level to be used&#x2F;generated. Each level has its own folder in <code>/worlds</code>.</td></tr><tr><td>level-seed</td><td>Any string</td><td></td><td>World creation</td><td>The seed to be used for randomizing the world. If left empty a seed will be chosen at random.</td></tr><tr><td>online-mode</td><td>true, false</td><td>true</td><td>Always</td><td>If true, all connected players must be authenticated with Xbox Live. Clients connecting to remote (non-LAN) servers will always require Xbox Live authentication regardless of this setting. If the server accepts connections from the Internet, then it is <strong>highly</strong> recommended to enable online-mode.</td></tr><tr><td>allow-list</td><td>true, false</td><td>false</td><td>Always</td><td>If true then all connected players must be listed in the separate <code>allowlist.json</code> file. See the <em>Allowlist</em> section.</td></tr><tr><td>view-distance</td><td>Any integer greater than 5</td><td>32</td><td>Always</td><td>The maximum allowed view distance. <strong>Higher values have performance impact.</strong></td></tr><tr><td>player-idle-timeout</td><td>Any positive integer, including 0</td><td>30</td><td>Always</td><td>After a player has idled for this many minutes they will be kicked. If set to 0 then players can idle indefinitely.</td></tr><tr><td>max-threads</td><td>Any integer</td><td>8</td><td>Always</td><td>Maximum number of threads the server will try to use. If set to 0 or removed then it will use as many as possible.</td></tr><tr><td>tick-distance</td><td>An integer in the range [4, 12]</td><td>4</td><td>Always</td><td>The world will be ticked this many chunks away from any player. <strong>Higher values have performance impact.</strong></td></tr><tr><td>default-player-permission-level</td><td>visitor, member, operator</td><td>member</td><td>Always</td><td>Which permission level new players will have when they join for the first time.</td></tr><tr><td>texturepack-required</td><td>true, false</td><td>false</td><td>Always</td><td>If the world uses any specific texture packs then this setting will force the client to use it.</td></tr><tr><td>content-log-file-enabled</td><td>true, false</td><td>false</td><td>Always</td><td>Enables logging content errors to a file.</td></tr><tr><td>compression-threshold</td><td>An integer in the range [0-65535]</td><td>1</td><td>Always</td><td>Determines the smallest size of raw network payload to compress. Can be used to experiment with CPU-bandwidth tradeoffs.</td></tr><tr><td>compression-algorithm</td><td>zlib, snappy</td><td>zlib</td><td>Always</td><td>Determines the compression algorithm to use for networking.</td></tr><tr><td>server-authoritative-movement-strict</td><td>true, false</td><td>false</td><td>Always</td><td>If true, will be more strict toward the Player position and be less permissive in accepting the client info. This will impact Player around moving block if there is high latency.</td></tr><tr><td>server-authoritative-dismount-strict</td><td>true, false</td><td>false</td><td>Always</td><td>If true, will be more strict toward the Player dismount position. This means clients will receive a correction on their dismount position in higher latency situation.</td></tr><tr><td>server-authoritative-entity-interactions-strict</td><td>true, false</td><td>false</td><td>Always</td><td>If true, will be more strict toward the Entity interactions. This will impact Players interacting with each other in higher latency situations.</td></tr><tr><td>player-position-acceptance-threshold</td><td>Any positive float</td><td>0.5</td><td>Always</td><td>This is the tolerance of discrepancies between the Client and Server Player position. This helps in problematic scenarios. The higher the number, the more tolerant the server will be before asking for a correction. Passed value of 1.0, the chance of missing cheating increases.</td></tr><tr><td>player-movement-action-direction-threshold</td><td>Any positive float in the range of [-1.00, 1.00]</td><td>0.85</td><td>Always</td><td>The amount that the direction the player is attacking can differ from the direction the player is looking as cos(x) where x is the angle between the two vectors. A value of 1 means the two vectors must be parallel, 0 means anything in front of the player, and -1 means any vector.</td></tr><tr><td>server-authoritative-block-breaking</td><td>true, false</td><td>false</td><td>Not when client-auth</td><td>If true, the server will compute block mining operations in sync with the client so it can verify that the client should be able to break blocks when it thinks it can. This setting cannot be combined with client authoritative movement and will be disabled if that setting is enabled.</td></tr><tr><td>server-authoritative-block-breaking-pick-range-scalar</td><td>Any float above 1.0</td><td>1.5</td><td>When server-authoritative-block-breaking is true</td><td>This increase the range of block breaking. This is squared and multiplied with the default range.</td></tr><tr><td>chat-restriction</td><td>None, Dropped, Disabled</td><td>None</td><td>Always</td><td>This represents the level of restriction applied to the chat for each player that joins the server. “None” is the default and represents regular free chat. “Dropped” means the chat messages are dropped and never sent to any client. Players receive a message to let them know the feature is disabled. “Disabled” means that unless the player is an operator, the chat UI does not even appear. No information is displayed to the player.</td></tr><tr><td>disable-player-interaction</td><td>true, false</td><td>false</td><td>Always</td><td>If true, the server will inform clients that they should ignore other players when interacting with the world. This is not server authoritative.</td></tr><tr><td>client-side-chunk-generation-enabled</td><td>true, false</td><td>true</td><td>Always</td><td>If true, the server will inform clients that they have the ability to generate visual level chunks outside of player interaction distances.</td></tr><tr><td>block-network-ids-are-hashes</td><td>true, false</td><td>true</td><td>Always</td><td>If true, the server will send hashed block network ID’s instead of id’s that start from 0 and go up. These id’s are stable and won’t change regardless of other block changes.</td></tr><tr><td>disable-persona</td><td>true, false</td><td>false</td><td>Internal Use Only</td><td></td></tr><tr><td>disable-custom-skins</td><td>true, false</td><td>false</td><td>Always</td><td>If true, disable players customized skins that were customized outside of the Minecraft store assets or in game assets. This is used to disable possibly offensive custom skins players make.</td></tr><tr><td>server-build-radius-ratio</td><td>Disabled, 0.0-1.0</td><td>Disabled</td><td>Always</td><td>If “Disabled” the server will dynamically calculate how much of the player’s view it will generate, assigning the rest to the client to build. Otherwise from the overridden ratio tell the server how much of the player’s view to generate, disregarding client hardware capability. <strong>Only valid if client-side-chunk-generation-enabled is enabled.</strong></td></tr></tbody></table><h1 id="文件夹"><a href="#文件夹" class="headerlink" title="文件夹"></a>文件夹</h1><p>解压后，您将看到几个文件夹和一个二进制可执行文件。首次启动服务器时，将创建一堆新的（空）文件夹。您需要关注的文件夹如下：</p><table><thead><tr><th>Folder name</th><th>Purpose</th></tr></thead><tbody><tr><td>behavior_packs</td><td>这里可以安装新的行为包。目前还无法在关卡中激活它们。</td></tr><tr><td>resource_packs</td><td>这里可以安装新的资源包。目前无法在关卡中激活它们。</td></tr><tr><td>worlds</td><td>如果此文件夹不存在，则会在启动时创建。每个创建的世界都会有一个根据其文件<code>level-name</code>内容命名的文件夹<code>server.properties</code>。</td></tr></tbody></table><h1 id="允许列表"><a href="#允许列表" class="headerlink" title="允许列表"></a>允许列表</h1><p>如果<code>allow-list</code>启用了此属性，<code>server.properties</code>则服务器将仅允许选定的用户连接。要允许用户连接，您需要知道他们的 Xbox Live 玩家代号。将用户添加到允许列表的最简单方法是使用命令<code>allowlist add &lt;Gamertag&gt;</code>（例如：）<code>allowlist add ExampleName</code>。注意：如果玩家代号中有空格，则需要用双引号将其括起来：<code>allowlist add &quot;Example Name&quot;</code></p><p>如果您稍后想从列表中删除某人，您可以使用命令<code>allowlist remove &lt;Gamertag&gt;</code>。</p><p>允许列表将保存在名为 的文件中<code>allowlist.json</code>。如果您想自动执行从中添加或删除玩家的过程，您可以这样做。修改文件后，您需要运行该命令<code>allowlist reload</code>以确保服务器知道您的新更改。</p><p>注意：此文件之前名为<code>whitelist.json</code>。为了向后兼容，如果<code>whitelist.json</code>存在其他文件，则将使用该文件代替<code>allowlist.json</code>。要迁移，请删除默认<code>allowlist.json</code>文件，重命名<code>whitelist.json</code>为<code>allowlist.json</code>，然后重启服务器。</p><p>该文件包含一个 JSON 数组，其中的对象包含以下键&#x2F;值。</p><table><thead><tr><th>Key</th><th>Type</th><th>Value</th></tr></thead><tbody><tr><td>name</td><td>String</td><td>用户的玩家代号。</td></tr><tr><td>xuid</td><td>String</td><td>可选。用户的 XUID。如果未设置，则当名称匹配的用户连接时，系统会填充该值。</td></tr><tr><td>ignoresPlayerLimit</td><td>Boolean</td><td>如果此用户不应计入最大玩家限制，则为 True。目前，即使玩家使用此选项，连接玩家数量仍存在另一个软限制，即 30 人（或比指定的最大玩家数量多 1 人）。此限制的目的是即使服务器已满，也能让一些玩家加入。</td></tr></tbody></table><p>示例 <code>allowlist.json</code> 文件:</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">[</span><br><span class="line">    &#123;</span><br><span class="line">        &quot;ignoresPlayerLimit&quot;: false,</span><br><span class="line">        &quot;name&quot;: &quot;MyPlayer&quot;</span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">        &quot;ignoresPlayerLimit&quot;: false,</span><br><span class="line">        &quot;name&quot;: &quot;AnotherPlayer&quot;,</span><br><span class="line">        &quot;xuid&quot;: &quot;274817248&quot;</span><br><span class="line">    &#125;</span><br><span class="line">]</span><br></pre></td></tr></table></figure><h1 id="权限"><a href="#权限" class="headerlink" title="权限"></a>权限</h1><p><code>permissions.json</code>您可以通过在与服务器可执行文件位于同一目录中的 中为玩家分配角色来调整玩家的特定权限。该文件包含一个带有 XUID 和权限的简单 JSON 对象。有效权限为： <code>operator</code>、<code>member</code>、<code>visitor</code>每个使用这些帐户连接的玩家都将根据设置的权限进行处理。如果您在服务器运行时更 ​​ 改此文件，请运行该命令<code>permission reload</code>以确保服务器知道您的新更改。您还可以使用 列出当前权限<code>permission list</code>。请注意，<code>online-mode</code>需要启用 才能使此功能正常工作，因为 xuid 需要对用户帐户进行在线验证。如果不在该列表中的新玩家连接，<code>default-player-permission-level</code> 则将应用该选项。</p><p>示例<code>permissions.json</code>文件：</p><figure class="highlight plaintext"><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></pre></td><td class="code"><pre><span class="line">[</span><br><span class="line">    &#123;</span><br><span class="line">        &quot;permission&quot;: &quot;operator&quot;,</span><br><span class="line">        &quot;xuid&quot;: &quot;451298348&quot;</span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">        &quot;permission&quot;: &quot;member&quot;,</span><br><span class="line">        &quot;xuid&quot;: &quot;52819329&quot;</span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">        &quot;permission&quot;: &quot;visitor&quot;,</span><br><span class="line">        &quot;xuid&quot;: &quot;234114123&quot;</span><br><span class="line">    &#125;</span><br><span class="line">]</span><br></pre></td></tr></table></figure><h1 id="崩溃报告"><a href="#崩溃报告" class="headerlink" title="崩溃报告"></a>崩溃报告</h1><p>如果服务器崩溃，它会自动向我们发送各种信息，帮助我们解决将来的问题。</p><h1 id="命令"><a href="#命令" class="headerlink" title="命令"></a>命令</h1><p>您可以通过在控制台中输入命令来向服务器发出命令。以下命令可用。&lt; &gt; 表示参数为必需参数，[ ] 表示参数为可选参数，| 表示不同的允许值。如果字符串包含空格，则可以用双引号 “ 括起来。</p><table><thead><tr><th>Command syntax</th><th>Description</th></tr></thead><tbody><tr><td>kick &lt; player name or xuid &gt; &lt; reason &gt;</td><td>立即踢出一名玩家。踢出原因将显示在被踢出玩家的屏幕上。</td></tr><tr><td>stop</td><td>正常关闭服务器。</td></tr></tbody></table><h1 id="备份"><a href="#备份" class="headerlink" title="备份"></a>备份</h1><p>服务器支持在运行时备份世界文件。手动备份不太方便，但自动备份效果更好。从服务器角度来看，备份包含三个命令。</p><table><thead><tr><th>Command</th><th>Description</th></tr></thead><tbody><tr><td>save hold</td><td>这将要求服务器准备备份。它是异步的，并将立即返回。</td></tr><tr><td>save query</td><td>调用此命令后，<code>save hold</code> 您应该反复调用该命令，以查看准备工作是否完成。如果返回成功，它将返回一个文件列表（包含每个文件的长度），其中包含您需要复制的文件。服务器在执行此操作时不会暂停，因此某些文件可能会在备份过程中被修改。只要您只复制给定文件列表中的文件，并将复制的文件截断为指定的长度，备份就应该是有效的。</td></tr><tr><td>save resume</td><td>当您完成文件复制后，您应该调用它来告诉服务器可以再次删除旧文件。</td></tr></tbody></table>]]>
    </content>
    <id>https://blog.zhangsifan.com/posts/20250424mc/</id>
    <link href="https://blog.zhangsifan.com/posts/20250424mc/"/>
    <published>2025-04-23T16:00:00.000Z</published>
    <summary>使用Ubuntu Linux搭建Minecraft基岩(Bedrock)服务器</summary>
    <title>零基础搭建Minecraft基岩(Bedrock)服务器</title>
    <updated>2026-03-31T03:22:20.637Z</updated>
  </entry>
  <entry>
    <author>
      <name>JCAlways</name>
    </author>
    <category term="开发工具" scheme="https://blog.zhangsifan.com/categories/%E5%BC%80%E5%8F%91%E5%B7%A5%E5%85%B7/"/>
    <category term="PageSpy" scheme="https://blog.zhangsifan.com/tags/PageSpy/"/>
    <content>
      <![CDATA[<p><a href="https://www.pagespy.org/#/">官方网站</a></p><h1 id="什么是-PageSpy？"><a href="#什么是-PageSpy？" class="headerlink" title="什么是 PageSpy？"></a>什么是 PageSpy？</h1><p>PageSpy 是一款兼容 Web &#x2F; 小程序 &#x2F; React Native &#x2F; 鸿蒙 App 等平台项目的开源调试平台。基于对原生 API 的封装，它将调用原生方法时的参数进行过滤、转化，整理成一定格式的消息供调试端消费；调试端收到消息数据后，提供类似本地控制台的功能界面将数据呈现出来。</p><h1 id="为什么是-PageSpy"><a href="#为什么是-PageSpy" class="headerlink" title="为什么是 PageSpy?"></a>为什么是 PageSpy?</h1><blockquote><p>一图胜千言。</p></blockquote><p><img src="https://www.pagespy.org/assets/why-is-pagespy-zh-C1-Ci1jQ.png"></p><h1 id="何时使用？"><a href="#何时使用？" class="headerlink" title="何时使用？"></a>何时使用？</h1><p>任何无法在本地使用控制台调试的场景，都是 PageSpy 可以大显身手的时候！ 一起来看下面的几个场景案例：</p><ul><li>本地调试 H5、Webview 应用：以往有些产品提供了可以在 H5 上查看信息的面板，但移动端屏幕太小操作不便、显示不友好，以及信息被截断等问题；</li><li>远程办公、跨地区协同：传统沟通方式如邮件、电话、视频会议等，沟通效率不高、故障信息不全面，容易误解误判；</li><li>用户终端上出现白屏问题：传统定位问题的方式包括数据监控、日志分析等，这些方式依赖排障人员要理解业务需求场景、技术实现；</li></ul><p>PageSpy 的目标，就是为包括以上场景的人员提供帮助。</p><h1 id="服务部署"><a href="#服务部署" class="headerlink" title="服务部署"></a>服务部署</h1><h2 id="使用-Docker-部署"><a href="#使用-Docker-部署" class="headerlink" title="使用 Docker 部署"></a>使用 Docker 部署</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run -d --restart=always -v ./log:/app/log -v ./data:/app/data -p 6752:6752 --name=<span class="string">&quot;pageSpy&quot;</span> ghcr.io/huolalatech/page-spy-web:latest</span><br></pre></td></tr></table></figure><p>执行完成后，打开浏览器访问 <a href="http://localhost:6752/">http://localhost:6752</a> 即可访问服务。</p><h2 id="视频学习"><a href="#视频学习" class="headerlink" title="视频学习"></a>视频学习</h2><iframe width="100%" height="550px" src="https://player.bilibili.com/player.html?isOutside=true&amp;aid=658778004&amp;bvid=BV1Ph4y1y78R&amp;cid=1209124922&amp;p=1" scrolling="no" allowfullscreen=""></iframe><h1 id="客户端部署"><a href="#客户端部署" class="headerlink" title="客户端部署"></a>客户端部署</h1><h2 id="浏览器"><a href="#浏览器" class="headerlink" title="浏览器"></a>浏览器</h2><h3 id="导入-SDK"><a href="#导入-SDK" class="headerlink" title="导入 SDK"></a>导入 SDK</h3><figure class="highlight js"><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></pre></td><td class="code"><pre><span class="line">&lt;!-- <span class="title class_">PageSpy</span> <span class="variable constant_">SDK</span> --&gt;</span><br><span class="line">&lt;script crossorigin=&quot;anonymous&quot; src=&quot;https://&lt;your-pagespy-host&gt;/page-spy/index.min.js&quot;&gt;&lt;/script&gt;</span><br><span class="line"></span><br><span class="line">&lt;!-- 插件（非必须，但建议使用） --&gt;</span><br><span class="line">&lt;script crossorigin=&quot;anonymous&quot; src=&quot;https://&lt;your-pagespy-host&gt;/plugin/data-harbor/index.min.js&quot;&gt;&lt;/script&gt;</span><br><span class="line">&lt;script crossorigin=&quot;anonymous&quot; src=&quot;https://&lt;your-pagespy-host&gt;/plugin/rrweb/index.min.js&quot;&gt;&lt;/script&gt;</span><br></pre></td></tr></table></figure><h3 id="初始化-PageSpy-和插件"><a href="#初始化-PageSpy-和插件" class="headerlink" title="初始化 PageSpy 和插件"></a>初始化 PageSpy 和插件</h3><figure class="highlight ts"><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></pre></td><td class="code"><pre><span class="line"><span class="variable language_">window</span>.<span class="property">$harbor</span> = <span class="keyword">new</span> <span class="title class_">DataHarborPlugin</span>();</span><br><span class="line"><span class="variable language_">window</span>.<span class="property">$rrweb</span> = <span class="keyword">new</span> <span class="title class_">RRWebPlugin</span>();</span><br><span class="line"></span><br><span class="line">[<span class="variable language_">window</span>.<span class="property">$harbor</span>, <span class="variable language_">window</span>.<span class="property">$rrweb</span>].<span class="title function_">forEach</span>(<span class="function">(<span class="params">p</span>) =&gt;</span> &#123;</span><br><span class="line">  <span class="title class_">PageSpy</span>.<span class="title function_">registerPlugin</span>(p);</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="variable language_">window</span>.<span class="property">$pageSpy</span> = <span class="keyword">new</span> <span class="title class_">PageSpy</span>(&#123;</span><br><span class="line">  <span class="comment">// 配置项</span></span><br><span class="line">  <span class="attr">api</span>?: <span class="built_in">string</span>;</span><br><span class="line">  <span class="attr">clientOrigin</span>?: <span class="built_in">string</span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// &quot;project&quot; is an aggregation of information that can be searched in the room list on the debug side.</span></span><br><span class="line">  <span class="comment">// default: &#x27;default&#x27;</span></span><br><span class="line">  <span class="attr">project</span>?: <span class="built_in">string</span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// &quot;title&quot; is a user-defined parameter that can be used to distinguish the current debugging client,</span></span><br><span class="line">  <span class="comment">// and the corresponding information is displayed under the &quot;device id&quot; in each debugging connection panel.</span></span><br><span class="line">  <span class="comment">// default: &#x27;--&#x27;</span></span><br><span class="line">  <span class="attr">title</span>?: <span class="built_in">string</span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// Indicates whether the SDK will automatically render the &quot;Circle with Logo on White Background&quot;</span></span><br><span class="line">  <span class="comment">// control in the bottom left corner of the client when initiation is complete. If set to false,</span></span><br><span class="line">  <span class="comment">// you can call window.$pageSpy.render() to render it manually.</span></span><br><span class="line">  <span class="comment">// default: true</span></span><br><span class="line">  <span class="attr">autoRender</span>?: <span class="built_in">boolean</span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// Manually specify the scheme of the PageSpy service.</span></span><br><span class="line">  <span class="comment">// This works if the SDK can&#x27;t correctly analyse the scheme, e.g. if PageSpy&#x27;s browser plugin</span></span><br><span class="line">  <span class="comment">// is introduced into the SDK via chrome-extension://xxx/sdk/index.min.js, which will be</span></span><br><span class="line">  <span class="comment">// be parsed by the SDK as an invalid &quot;chrome-extension://&quot; and fallback to [&quot;http://&quot;, &quot;ws://&quot;].</span></span><br><span class="line">  <span class="comment">//   - (Default) Pass the value undefined or null: the SDK will parse it automatically;</span></span><br><span class="line">  <span class="comment">//   - Pass boolean value:</span></span><br><span class="line">  <span class="comment">//     - true: the SDK will access the PageSpy service via [&quot;https://&quot;, &quot;wss://&quot;].</span></span><br><span class="line">  <span class="comment">//     - false: the SDK will access the PageSpy service via [&quot;http://&quot;, &quot;wss://&quot;]</span></span><br><span class="line">  <span class="attr">enableSSL</span>?: <span class="built_in">boolean</span> | <span class="literal">null</span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// All internal plugins are carried with PageSpy by default out of the box.</span></span><br><span class="line">  <span class="comment">// You can disable some plugins as needed.</span></span><br><span class="line">  <span class="attr">disabledPlugins</span>?: (<span class="title class_">InternalPlugins</span> | <span class="built_in">string</span>)[];</span><br><span class="line"></span><br><span class="line">  <span class="comment">// After adding support for offline replay in PageSpy@1.7.4, the client-integrated SDK can work without</span></span><br><span class="line">  <span class="comment">// establishing a connection with the debugger.</span></span><br><span class="line">  <span class="comment">// Default value is false, when users set it to other values will enters &quot;offline mode&quot;, where PageSpy</span></span><br><span class="line">  <span class="comment">// will not create rooms or establish WebSocket connections.</span></span><br><span class="line">  <span class="attr">offline</span>?: <span class="built_in">boolean</span>;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// Customize logo source url.</span></span><br><span class="line">  <span class="attr">logo</span>?: <span class="built_in">string</span>;</span><br><span class="line"></span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><h2 id="小程序"><a href="#小程序" class="headerlink" title="小程序"></a>小程序</h2><h3 id="导入-SDK-1"><a href="#导入-SDK-1" class="headerlink" title="导入 SDK"></a>导入 SDK</h3><p>在项目中安装依赖。我们提供了几种小程序平台的 SDK，请根据需要安装：</p><ul><li>微信小程序</li></ul><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yarn add @huolala-tech/page-spy-wechat@latest</span><br></pre></td></tr></table></figure><ul><li>支付宝小程序</li></ul><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yarn add @huolala-tech/page-spy-alipay@latest</span><br></pre></td></tr></table></figure><ul><li>UniAPP</li></ul><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yarn add @huolala-tech/page-spy-uniapp@latest</span><br></pre></td></tr></table></figure><ul><li>Taro</li></ul><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">yarn add @huolala-tech/page-spy-taro@latest</span><br></pre></td></tr></table></figure><h3 id="配置白名单"><a href="#配置白名单" class="headerlink" title="配置白名单"></a>配置白名单</h3><p>将 PageSpy 服务域名填入小程序的 http、websocket 请求白名单中。注意除了开发环境，小程序强制要求使用 https 和 wss 协议：</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">https://&lt;your-pagespy-host&gt;</span><br><span class="line">wss://&lt;your-pagespy-host&gt;</span><br></pre></td></tr></table></figure><h3 id="初始化-PageSpy-和插件-1"><a href="#初始化-PageSpy-和插件-1" class="headerlink" title="初始化 PageSpy 和插件"></a>初始化 PageSpy 和插件</h3><p>在入口文件中引入 SDK 并实例化，初始化参数提供了可选的 配置项 用于自定义 SDK 的行为：</p><figure class="highlight js"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="title class_">PageSpy</span> <span class="keyword">from</span> <span class="string">&quot;@huolala-tech/page-spy-wechat&quot;</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> $pageSpy = <span class="keyword">new</span> <span class="title class_">PageSpy</span>(&#123;</span><br><span class="line">  <span class="attr">api</span>: <span class="string">&quot;&lt;your-pagespy-host&gt;&quot;</span>,</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><h2 id="鸿蒙-App"><a href="#鸿蒙-App" class="headerlink" title="鸿蒙 App"></a>鸿蒙 App</h2><h3 id="导入-SDK-2"><a href="#导入-SDK-2" class="headerlink" title="导入 SDK"></a>导入 SDK</h3><p>在待调试 HAP 目录下安装依赖：</p><figure class="highlight shell"><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></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">API 9</span></span><br><span class="line">ohpm install @huolala/page-spy-harmony@^1.0.0</span><br><span class="line"><span class="meta prompt_"></span></span><br><span class="line"><span class="meta prompt_"># </span><span class="language-bash">API 11</span></span><br><span class="line">ohpm install @huolala/page-spy-harmony@^2</span><br></pre></td></tr></table></figure><h3 id="初始化-PageSpy-和插件-2"><a href="#初始化-PageSpy-和插件-2" class="headerlink" title="初始化 PageSpy 和插件"></a>初始化 PageSpy 和插件</h3><p>在合适的位置引入 SDK 并初始化，这里以 EntryAbility 为例。初始化参数提供了可选的 配置项 用于自定义 SDK 的行为：</p><figure class="highlight js"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">PageSpy</span> &#125; <span class="keyword">from</span> <span class="string">&quot;@huolala/page-spy-harmony&quot;</span>;</span><br><span class="line"><span class="keyword">import</span> axiosInstance <span class="keyword">from</span> <span class="string">&quot;path/to/your/axios-instance&quot;</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> <span class="keyword">class</span> <span class="title class_">EntryAbility</span> <span class="keyword">extends</span> <span class="title class_ inherited__">UIAbility</span> &#123;</span><br><span class="line">  <span class="title function_">onWindowStageCreate</span>(<span class="params">windowStage: <span class="variable language_">window</span>.WindowStage</span>) &#123;</span><br><span class="line">    <span class="keyword">new</span> <span class="title class_">PageSpy</span>(&#123;</span><br><span class="line">      <span class="attr">context</span>: <span class="variable language_">this</span>.<span class="property">context</span>,</span><br><span class="line">      <span class="attr">api</span>: <span class="string">&quot;&lt;your-pagespy-host&gt;&quot;</span>,</span><br><span class="line">      <span class="attr">enableSSL</span>: <span class="literal">true</span>,</span><br><span class="line">      <span class="attr">axios</span>: axiosInstance,</span><br><span class="line">    &#125;);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="常用-API"><a href="#常用-API" class="headerlink" title="常用 API"></a>常用 API</h1><h2 id="更新初始化参数"><a href="#更新初始化参数" class="headerlink" title="更新初始化参数"></a>更新初始化参数</h2><p>PageSpy 提供了 Device ID 用于识别设备，同时还提供了 project &#x2F; title 供开发者在初始化时自定义信息，用于辅助识别客户端。但你可能希望在初始化之后更新这些参数信息，操作方式如下：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 调用 updateRoomInfo 可以更新 project / title</span></span><br><span class="line"><span class="variable language_">window</span>.<span class="property">$pageSpy</span>.<span class="title function_">updateRoomInfo</span>(&#123; <span class="attr">project</span>: <span class="string">&quot;xxx&quot;</span>, <span class="attr">title</span>: <span class="string">&quot;xxx&quot;</span> &#125;);</span><br></pre></td></tr></table></figure><h2 id="显示隐藏按钮"><a href="#显示隐藏按钮" class="headerlink" title="显示隐藏按钮"></a>显示隐藏按钮</h2><figure class="highlight js"><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></pre></td><td class="code"><pre><span class="line"><span class="variable language_">window</span>.<span class="property">$pageSpy</span> = <span class="keyword">new</span> <span class="title class_">PageSpy</span>(&#123;</span><br><span class="line">  <span class="comment">// ... 其他配置参数</span></span><br><span class="line">  <span class="attr">autoRender</span>: <span class="literal">false</span>,</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><h3 id="手动渲染「圆形白底带-Logo」的控件"><a href="#手动渲染「圆形白底带-Logo」的控件" class="headerlink" title="手动渲染「圆形白底带 Logo」的控件"></a>手动渲染「圆形白底带 Logo」的控件</h3><blockquote><p>当 <code>config.autoRender</code> 为 <code>false</code> 时，需要手动调用 <code>render()</code> 方法渲染控件。</p></blockquote><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable language_">window</span>.<span class="property">$pageSpy</span>.<span class="title function_">render</span>();</span><br></pre></td></tr></table></figure><h3 id="销毁"><a href="#销毁" class="headerlink" title="销毁"></a>销毁</h3><blockquote><p>PageSpy 会断开连接、从文档中移除相关 DOM、清空已缓存的数据、调用所有已注册插件的 onReset() 方法。<br>当前上下文中被代理或者被重写的 API，如浏览器中的 window.fetch，都会恢复到实例化 PageSpy 之前的状态。</p></blockquote><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable language_">window</span>.<span class="property">$pageSpy</span>.<span class="title function_">abort</span>();</span><br></pre></td></tr></table></figure><h1 id="常见问题"><a href="#常见问题" class="headerlink" title="常见问题"></a>常见问题</h1><h2 id="调试端如何加一些安全认证的保护，开发者通过认证才可以访问？"><a href="#调试端如何加一些安全认证的保护，开发者通过认证才可以访问？" class="headerlink" title="调试端如何加一些安全认证的保护，开发者通过认证才可以访问？"></a>调试端如何加一些安全认证的保护，开发者通过认证才可以访问？</h2><p>从 2.3.0 版本开始，PageSpy 支持在启动服务时使用变量设置密码以保护调试端安全。设置密码后，开发者访问调试面板时必须输入正确的密码。</p><p>允许输入的变量和含义：</p><ul><li>AUTH_PASSWORD：设置密码；</li><li>JWT_SECRET：设置 token 的密钥；</li><li>JWT_EXPIRATION_HOURS：设置 token 过期时间（小时），默认 24 小时；</li></ul><p>在启动服务时设置，具体的使用方式如下：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">docker run -d --restart=always -v ./log:/app/log -v ./data:/app/data -p 6752:6752 --name=&quot;pageSpy&quot; -e AUTH_PASSWORD=&lt;password&gt; -e JWT_SECRET=&lt;secret&gt; -e JWT_EXPIRATION_HOURS=&lt;hours&gt; ghcr.io/huolalatech/page-spy-web:latest</span><br></pre></td></tr></table></figure><h3 id="2-3-0-之前的版本如何设置密码？"><a href="#2-3-0-之前的版本如何设置密码？" class="headerlink" title="2.3.0 之前的版本如何设置密码？"></a>2.3.0 之前的版本如何设置密码？</h3><figure class="highlight nginx"><figcaption><span>配置</span></figcaption><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">auth_basic</span> <span class="string">&quot;请输入用户名和密码以访问 PageSpy 服务&quot;</span>;</span><br><span class="line"><span class="attribute">auth_basic_user_file</span> /etc/nginx/.htpasswd;</span><br></pre></td></tr></table></figure><h2 id="预览页面-CORS"><a href="#预览页面-CORS" class="headerlink" title="预览页面 CORS"></a>预览页面 CORS</h2><figure class="highlight yml"><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></pre></td><td class="code"><pre><span class="line"><span class="string">server</span></span><br><span class="line">&#123;</span><br><span class="line">  <span class="comment"># 设置CORS</span></span><br><span class="line">  <span class="comment"># 指定响应资源是否允许与给定的 origin 共享</span></span><br><span class="line">  <span class="string">add_header</span> <span class="string">Access-Control-Allow-Origin</span> <span class="string">&#x27;*&#x27;</span><span class="string">;</span></span><br><span class="line">  <span class="string">add_header</span> <span class="string">Access-Control-Allow-Credentials</span> <span class="string">&#x27;true&#x27;</span><span class="string">;</span></span><br><span class="line">  <span class="comment"># 配置允许跨域的请求方法</span></span><br><span class="line">  <span class="string">add_header</span> <span class="string">Access-Control-Allow-Methods</span> <span class="string">&#x27;GET,POST,PUT,DELETE,Options&#x27;</span><span class="string">;</span></span><br><span class="line">  <span class="comment"># 配置允许跨域的请求头</span></span><br><span class="line">  <span class="comment"># add_header Access-Control-Allow-Headers &#x27;Authorization,Content-Type,Accept,Origin,User-Agent,Cache-Control,X-Mx-ReqToken,X-Requested-With&#x27;;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="更改按钮大小和图片大小"><a href="#更改按钮大小和图片大小" class="headerlink" title="更改按钮大小和图片大小"></a>更改按钮大小和图片大小</h2><figure class="highlight css"><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></pre></td><td class="code"><pre><span class="line"><span class="selector-id">#__pageSpy</span> <span class="selector-class">.page-spy-logo</span> &#123;</span><br><span class="line">  <span class="attribute">width</span>: <span class="number">50px</span>;</span><br><span class="line">  <span class="attribute">height</span>: <span class="number">50px</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="selector-id">#__pageSpy</span> <span class="selector-class">.page-spy-logo</span> <span class="selector-tag">img</span> &#123;</span><br><span class="line">  <span class="attribute">width</span>: <span class="number">30px</span>;</span><br><span class="line">  <span class="attribute">height</span>: <span class="number">30px</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="主题-个性化-设置"><a href="#主题-个性化-设置" class="headerlink" title="主题(个性化)设置"></a>主题(个性化)设置</h2><figure class="highlight js"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">new</span> <span class="title class_">PageSpy</span>(&#123;</span><br><span class="line">  ...,</span><br><span class="line">  <span class="attr">primaryColor</span>: <span class="string">&quot;&lt;主题色&gt;&quot;</span>,</span><br><span class="line">  <span class="attr">logo</span>: <span class="string">&quot;&lt;悬浮球上的 logo&gt;&quot;</span>,</span><br><span class="line">  <span class="attr">modal</span>: &#123;</span><br><span class="line">    <span class="attr">title</span>: <span class="string">&quot;&lt;弹窗上的标题&gt;&quot;</span>,</span><br><span class="line">    <span class="attr">logo</span>: <span class="string">&quot;&lt;弹窗上的 logo&gt;&quot;</span>,</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>]]>
    </content>
    <id>https://blog.zhangsifan.com/posts/20241017dv/</id>
    <link href="https://blog.zhangsifan.com/posts/20241017dv/"/>
    <published>2024-10-16T16:00:00.000Z</published>
    <summary>像使用谷歌浏览器的控制台一样简单地开始远程调试。</summary>
    <title>PageSpy使用教程</title>
    <updated>2026-03-31T03:22:20.637Z</updated>
  </entry>
  <entry>
    <author>
      <name>JCAlways</name>
    </author>
    <category term="辅助类" scheme="https://blog.zhangsifan.com/categories/%E8%BE%85%E5%8A%A9%E7%B1%BB/"/>
    <content>
      <![CDATA[<p><a href="https://flingtrainer.com/">官方网站</a></p><h2 id="黑神话悟空-Black-Myth-Wukong-Trainer"><a href="#黑神话悟空-Black-Myth-Wukong-Trainer" class="headerlink" title="黑神话悟空 - Black Myth: Wukong Trainer"></a>黑神话悟空 - Black Myth: Wukong Trainer</h2><p><a href="https://static.zhangsifan.com/files/wukong.exe">Black.Myth.Wukong.v1.0-v1.0.9.Plus.44.Trainer-FLiNG</a></p><h2 id="荒野大镖客-2-Red-Dead-Redemption-2"><a href="#荒野大镖客-2-Red-Dead-Redemption-2" class="headerlink" title="荒野大镖客 2 - Red Dead Redemption 2"></a>荒野大镖客 2 - Red Dead Redemption 2</h2><p><a href="https://static.zhangsifan.com/files/red.exe">Red.Dead.Redemption.2.v1.0-v1491.50.Plus.12.Trainer-FLiNG</a></p><h2 id="侠盗猎车手-5-Grand-Theft-Auto-V"><a href="#侠盗猎车手-5-Grand-Theft-Auto-V" class="headerlink" title="侠盗猎车手 5 - Grand Theft Auto V"></a>侠盗猎车手 5 - Grand Theft Auto V</h2><p><a href="https://static.zhangsifan.com/files/gta5.rar">Grand.Theft.Auto.V.v1.0-v1.69.Plus.19.Trainer-FLiNG</a></p><h2 id="赛博朋克-2077-Cyberpunk-2077"><a href="#赛博朋克-2077-Cyberpunk-2077" class="headerlink" title="赛博朋克 2077 - Cyberpunk 2077"></a>赛博朋克 2077 - Cyberpunk 2077</h2><p><a href="https://static.zhangsifan.com/files/2077.exe">Cyberpunk.2077.v2.0-v2.13.Plus.46.Trainer-FLiNG</a></p>]]>
    </content>
    <id>https://blog.zhangsifan.com/posts/20240924wg/</id>
    <link href="https://blog.zhangsifan.com/posts/20240924wg/"/>
    <published>2024-09-23T16:00:00.000Z</published>
    <summary>风灵月影辅助下载</summary>
    <title>风灵月影下载</title>
    <updated>2026-03-31T03:22:20.637Z</updated>
  </entry>
  <entry>
    <author>
      <name>JCAlways</name>
    </author>
    <category term="验证类" scheme="https://blog.zhangsifan.com/categories/%E9%AA%8C%E8%AF%81%E7%B1%BB/"/>
    <category term="reCAPTCHA" scheme="https://blog.zhangsifan.com/tags/reCAPTCHA/"/>
    <content>
      <![CDATA[<p><a href="https://www.google.com/recaptcha/about/">官方网站</a></p><h1 id="基于得分-v3"><a href="#基于得分-v3" class="headerlink" title="基于得分 (v3)"></a>基于得分 (v3)</h1><h2 id="示例"><a href="#示例" class="headerlink" title="示例"></a>示例</h2><style>.grecaptcha-badge {  visibility: hidden;}</style><script src="https://www.recaptcha.net/recaptcha/api.js?render=6LfWnrwpAAAAAABWBUfPCn9qB6C0vH6K4A7oEz6d"  async defer></script><div id="v3_text">正在自动验证中...</div><script>function openV3() {  grecaptcha.ready(() => {    grecaptcha      .execute("6LfWnrwpAAAAAABWBUfPCn9qB6C0vH6K4A7oEz6d", { action: "submit" })      .then(async (token) => {        await fetch("https://api.zhangsifan.com/google/getReCAPTCHA", {          method: "POST",          body: JSON.stringify({            token: token,            id: "6LfWnrwpAAAAAABWBUfPCn9qB6C0vH6K4A7oEz6d",          }),          headers: {            "Content-Type": "application/json",          },        }).then(async (response) => {          const { result } = await response.json();          console.log(result);          document.getElementById("v3_text").innerText = result.success ? "验证成功,得分为" + result.score  : "验证失败";        });      });  });}setTimeout(() => openV3(), 3000);</script><h2 id="以编程方式调用验证方式"><a href="#以编程方式调用验证方式" class="headerlink" title="以编程方式调用验证方式"></a>以编程方式调用验证方式</h2><blockquote><p>如果您希望更好地控制 reCAPTCHA 的运行时间，可以在 grecaptcha 对象中使用 execute 方法。为此，您需要在 reCAPTCHA 脚本加载中添加 render 参数。</p></blockquote><ul><li><p>使用您的网站密钥加载 JavaScript API。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">&lt;script src=<span class="string">&quot;https://www.google.com/recaptcha/api.js?render=reCAPTCHA_site_key&quot;</span>&gt;&lt;/script&gt;</span><br><span class="line"><span class="comment">// 如无法连接 Google 服务器，请使用以下地址。</span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">&quot;https://recaptcha.net/recaptcha/api.js?render=reCAPTCHA_site_key&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span></span><br></pre></td></tr></table></figure></li><li><p>针对您要保护的每项操作调用 grecaptcha.execute。</p><figure class="highlight js"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">function</span> <span class="title function_">onClick</span>(<span class="params">e</span>) &#123;</span><br><span class="line">  e.<span class="title function_">preventDefault</span>();</span><br><span class="line">  grecaptcha.<span class="title function_">ready</span>(<span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">    grecaptcha</span><br><span class="line">      .<span class="title function_">execute</span>(<span class="string">&quot;reCAPTCHA_site_key&quot;</span>, &#123; <span class="attr">action</span>: <span class="string">&quot;submit&quot;</span> &#125;)</span><br><span class="line">      .<span class="title function_">then</span>(<span class="keyword">function</span> (<span class="params">token</span>) &#123;</span><br><span class="line">        <span class="comment">// Add your logic to submit to your backend server here.</span></span><br><span class="line">      &#125;);</span><br><span class="line">  &#125;);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>在您的后端验证 reCAPTCHA 令牌。</p><figure class="highlight js"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> &#123;</span><br><span class="line"><span class="string">&quot;success&quot;</span>: <span class="literal">true</span>|<span class="literal">false</span>,      <span class="comment">// whether this request was a valid reCAPTCHA token for your site</span></span><br><span class="line"><span class="string">&quot;score&quot;</span>: number             <span class="comment">// the score for this request (0.0 - 1.0)</span></span><br><span class="line"><span class="string">&quot;action&quot;</span>: string            <span class="comment">// the action name for this request (important to verify)</span></span><br><span class="line"><span class="string">&quot;challenge_ts&quot;</span>: timestamp,  <span class="comment">// timestamp of the challenge load (ISO format yyyy-MM-dd&#x27;T&#x27;HH:mm:ssZZ)</span></span><br><span class="line"><span class="string">&quot;hostname&quot;</span>: string,         <span class="comment">// the hostname of the site where the reCAPTCHA was solved</span></span><br><span class="line"><span class="string">&quot;error-codes&quot;</span>: [...]        <span class="comment">// optional</span></span><br><span class="line">&#125; = <span class="keyword">await</span> <span class="title function_">fetch</span>(<span class="string">&quot;https://www.google.com/recaptcha/api/siteverify&quot;</span>, &#123;</span><br><span class="line">  <span class="attr">method</span>: <span class="string">&quot;POST&quot;</span>,</span><br><span class="line">  <span class="attr">headers</span>: &#123;</span><br><span class="line">    <span class="string">&quot;Content-Type&quot;</span>: <span class="string">&quot;application/x-www-form-urlencoded; charset=utf-8&quot;</span>,</span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="attr">body</span>: <span class="string">`secret=your_secret&amp;response=<span class="subst">$&#123;token&#125;</span>`</span>,</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure></li></ul><h1 id="基于验证方式-v2"><a href="#基于验证方式-v2" class="headerlink" title="基于验证方式 (v2)"></a>基于验证方式 (v2)</h1><h2 id="示例-1"><a href="#示例-1" class="headerlink" title="示例"></a>示例</h2><style>.grecaptcha-badge {  visibility: hidden;}</style><script src="https://www.recaptcha.net/recaptcha/api.js?render=6LfWnrwpAAAAAABWBUfPCn9qB6C0vH6K4A7oEz6d"  async defer></script><div id="html_element"></div><script>function open() {  grecaptcha.render("html_element", {    sitekey: "6Lf2irwpAAAAAIfBI_Bjo7TAccpnUAPsiI01rF7x",    callback: async function (response) {      await fetch("https://api.zhangsifan.com/google/getReCAPTCHA", {        method: "POST",        body: JSON.stringify({          token: response,          id: "6Lf2irwpAAAAAIfBI_Bjo7TAccpnUAPsiI01rF7x",        }),        headers: {          "Content-Type": "application/json",        },      }).then(async (response) => {        const { result } = await response.json();        if (result.success) {          if (window.confirm("验证成功,是否重置验证器?")) {            grecaptcha.reset();          }        } else {          window.alert("验证失败,是否重置验证器?");          grecaptcha.reset();        }      });    },  });}setTimeout(() => open(), 3000);</script><h2 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h2><figure class="highlight html"><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></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">html</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">head</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">title</span>&gt;</span>reCAPTCHA<span class="tag">&lt;/<span class="name">title</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span></span></span><br><span class="line"><span class="tag">      <span class="attr">src</span>=<span class="string">&quot;https://www.recaptcha.net/recaptcha/api.js&quot;</span></span></span><br><span class="line"><span class="tag">      <span class="attr">async</span></span></span><br><span class="line"><span class="tag">      <span class="attr">defer</span></span></span><br><span class="line"><span class="tag">    &gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">head</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">body</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;html_element&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">      <span class="keyword">function</span> <span class="title function_">open</span>(<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">        grecaptcha.<span class="title function_">render</span>(<span class="string">&quot;html_element&quot;</span>, &#123;</span></span><br><span class="line"><span class="language-javascript">          <span class="attr">sitekey</span>: <span class="string">&quot;reCAPTCHA_site_key&quot;</span>,</span></span><br><span class="line"><span class="language-javascript">          <span class="attr">callback</span>: <span class="keyword">async</span> <span class="keyword">function</span> (<span class="params">response</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">            <span class="keyword">await</span> <span class="title function_">fetch</span>(<span class="string">&quot;https://api.zhangsifan.com/google/getReCAPTCHA&quot;</span>, &#123;</span></span><br><span class="line"><span class="language-javascript">              <span class="attr">method</span>: <span class="string">&quot;POST&quot;</span>,</span></span><br><span class="line"><span class="language-javascript">              <span class="attr">body</span>: <span class="title class_">JSON</span>.<span class="title function_">stringify</span>(&#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="attr">token</span>: response,</span></span><br><span class="line"><span class="language-javascript">                <span class="attr">id</span>: <span class="string">&quot;reCAPTCHA_site_key&quot;</span>,</span></span><br><span class="line"><span class="language-javascript">              &#125;),</span></span><br><span class="line"><span class="language-javascript">              <span class="attr">headers</span>: &#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="string">&quot;Content-Type&quot;</span>: <span class="string">&quot;application/json&quot;</span>,</span></span><br><span class="line"><span class="language-javascript">              &#125;,</span></span><br><span class="line"><span class="language-javascript">            &#125;).<span class="title function_">then</span>(<span class="title function_">async</span> (response) =&gt; &#123;</span></span><br><span class="line"><span class="language-javascript">              <span class="keyword">const</span> &#123; result &#125; = <span class="keyword">await</span> response.<span class="title function_">json</span>();</span></span><br><span class="line"><span class="language-javascript">              <span class="keyword">if</span> (result.<span class="property">success</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="keyword">if</span> (<span class="variable language_">window</span>.<span class="title function_">confirm</span>(<span class="string">&quot;验证成功,是否重置验证器?&quot;</span>)) &#123;</span></span><br><span class="line"><span class="language-javascript">                  grecaptcha.<span class="title function_">reset</span>();</span></span><br><span class="line"><span class="language-javascript">                &#125;</span></span><br><span class="line"><span class="language-javascript">              &#125; <span class="keyword">else</span> &#123;</span></span><br><span class="line"><span class="language-javascript">                <span class="variable language_">window</span>.<span class="title function_">alert</span>(<span class="string">&quot;验证失败,是否重置验证器?&quot;</span>);</span></span><br><span class="line"><span class="language-javascript">                grecaptcha.<span class="title function_">reset</span>();</span></span><br><span class="line"><span class="language-javascript">              &#125;</span></span><br><span class="line"><span class="language-javascript">            &#125;);</span></span><br><span class="line"><span class="language-javascript">          &#125;,</span></span><br><span class="line"><span class="language-javascript">        &#125;);</span></span><br><span class="line"><span class="language-javascript">      &#125;</span></span><br><span class="line"><span class="language-javascript">      <span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> <span class="title function_">open</span>(), <span class="number">3000</span>);</span></span><br><span class="line"><span class="language-javascript">    </span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;/<span class="name">body</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">html</span>&gt;</span></span><br></pre></td></tr></table></figure>]]>
    </content>
    <id>https://blog.zhangsifan.com/posts/20240417re/</id>
    <link href="https://blog.zhangsifan.com/posts/20240417re/"/>
    <published>2024-04-16T16:00:00.000Z</published>
    <summary>reCAPTCHA使用先进的风险分析引擎和自适应挑战来防止恶意软件在您的网站上进行滥用活动。与此同时，合法用户将能够登录、购买、查看页面或创建帐户，而虚假用户将被屏蔽。</summary>
    <title>Google reCAPTCHA使用教程</title>
    <updated>2026-03-31T03:22:20.637Z</updated>
  </entry>
  <entry>
    <author>
      <name>JCAlways</name>
    </author>
    <category term="通行秘钥" scheme="https://blog.zhangsifan.com/tags/%E9%80%9A%E8%A1%8C%E7%A7%98%E9%92%A5/"/>
    <content>
      <![CDATA[<p><a href="https://developers.google.com/codelabs/passkey-form-autofill?hl=zh-cn#0">使用文档</a></p><blockquote><p>网站通过使用通行密钥代替密码，可提高用户帐号的安全性并简化用户帐号的管理和使用。借助通行密钥，用户可以使用设备的屏幕锁定功能（例如指纹锁、人脸识别锁或设备 PIN 码）来登录网站或应用。必须先创建通行密钥、将其与用户帐号关联，并将其公钥存储在服务器上，之后用户才能使用该通行密钥进行登录。</p></blockquote><h1 id="示例"><a href="#示例" class="headerlink" title="示例"></a>示例</h1><blockquote><p><a href="https://account.zhangsifan.com/">示例网站</a></p></blockquote><iframe style="border: none;width:100%;height:800px;"  src="https://account.zhangsifan.com/" allow="publickey-credentials-create; publickey-credentials-get; clipboard-write" ></iframe><h1 id="代码实现"><a href="#代码实现" class="headerlink" title="代码实现"></a>代码实现</h1><h2 id="前端代码"><a href="#前端代码" class="headerlink" title="前端代码"></a>前端代码</h2><h3 id="安装依赖库"><a href="#安装依赖库" class="headerlink" title="安装依赖库"></a>安装依赖库</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install @simplewebauthn/browser</span><br></pre></td></tr></table></figure><h3 id="后端需实现的接口"><a href="#后端需实现的接口" class="headerlink" title="后端需实现的接口"></a>后端需实现的接口</h3><h4 id="注册验证器"><a href="#注册验证器" class="headerlink" title="注册验证器"></a>注册验证器</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">从依赖方（您的服务器）获取注册选项 (/passkey/generate-registration-options)</span><br><span class="line">将身份验证者的回复提交给依赖方进行验证 (/passkey/verify-registration)</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="使用验证器"><a href="#使用验证器" class="headerlink" title="使用验证器"></a>使用验证器</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">从依赖方（您的服务器）获取身份验证选项 (/passkey/generate-authentication-options)</span><br><span class="line">将身份验证者的回复提交给依赖方进行验证 (/passkey/verify-authentication)</span><br></pre></td></tr></table></figure><h3 id="示例代码"><a href="#示例代码" class="headerlink" title="示例代码"></a>示例代码</h3><figure class="highlight ts"><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><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  <span class="language-xml"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;container&quot;</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">    <span class="tag">&lt;<span class="name">el-input</span></span></span></span><br><span class="line"><span class="tag"><span class="language-xml">      <span class="attr">v-model.trim</span>=<span class="string">&quot;state.uniid&quot;</span></span></span></span><br><span class="line"><span class="tag"><span class="language-xml">      <span class="attr">style</span>=<span class="string">&quot;width: 300px&quot;</span></span></span></span><br><span class="line"><span class="tag"><span class="language-xml">      <span class="attr">placeholder</span>=<span class="string">&quot;请输入用户唯一标识符/邮箱账号&quot;</span></span></span></span><br><span class="line"><span class="tag"><span class="language-xml">    /&gt;</span></span></span><br><span class="line"><span class="language-xml">    <span class="tag">&lt;<span class="name">el-button</span> @<span class="attr">click</span>=<span class="string">&quot;init&quot;</span> <span class="attr">:disabled</span>=<span class="string">&quot;!state.uniid&quot;</span>&gt;</span>创建通行密钥<span class="tag">&lt;/<span class="name">el-button</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">    <span class="tag">&lt;<span class="name">el-button</span> @<span class="attr">click</span>=<span class="string">&quot;login&quot;</span>&gt;</span>通过通行密钥登录<span class="tag">&lt;/<span class="name">el-button</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">  <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">&lt;/template&gt;</span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">script</span> <span class="attr">setup</span> <span class="attr">lang</span>=<span class="string">&quot;ts&quot;</span>&gt;</span><span class="language-javascript"></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="keyword">import</span> &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  reactive,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  onMounted,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  getCurrentInstance,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  type <span class="title class_">ComponentInternalInstance</span>,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">&#125; <span class="keyword">from</span> <span class="string">&quot;vue&quot;</span>;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="keyword">import</span> &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  startRegistration,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  startAuthentication,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">&#125; <span class="keyword">from</span> <span class="string">&quot;@simplewebauthn/browser&quot;</span>;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="keyword">import</span> &#123; <span class="title class_">ElMessage</span> &#125; <span class="keyword">from</span> <span class="string">&quot;element-plus&quot;</span>;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="keyword">const</span> currentInstance = <span class="title function_">getCurrentInstance</span>() <span class="keyword">as</span> <span class="title class_">ComponentInternalInstance</span>;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="keyword">const</span> &#123; $UtilsHttp &#125; = currentInstance.<span class="property">appContext</span>.<span class="property">config</span>.<span class="property">globalProperties</span>;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="keyword">const</span> state = <span class="title function_">reactive</span>(&#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  <span class="attr">uniid</span>: <span class="string">&quot;&quot;</span>,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">&#125;);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="keyword">const</span> <span class="title function_">init</span> = <span class="keyword">async</span> (<span class="params"></span>) =&gt; &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  <span class="keyword">try</span> &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="keyword">const</span> &#123; result &#125; = <span class="keyword">await</span> $UtilsHttp(</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">      <span class="string">&quot;/passkey/generate-registration-options&quot;</span>,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">      <span class="string">&quot;get&quot;</span>,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">      &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="attr">uniid</span>: state.<span class="property">uniid</span>,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">      &#125;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    );</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="keyword">const</span> challenge = result.<span class="property">challenge</span>;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="keyword">let</span> attResp;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="keyword">try</span> &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">      attResp = <span class="keyword">await</span> <span class="title function_">startRegistration</span>(result);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    &#125; <span class="keyword">catch</span> (error) &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">      <span class="keyword">if</span> (error.<span class="property">name</span> === <span class="string">&quot;InvalidStateError&quot;</span>) &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="title class_">ElMessage</span>.<span class="title function_">error</span>(</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">          <span class="string">&quot;Authenticator was probably already registered by user&quot;</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        );</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">      &#125; <span class="keyword">else</span> &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="title class_">ElMessage</span>.<span class="title function_">error</span>(error.<span class="title function_">toString</span>());</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">      &#125;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">      <span class="keyword">throw</span> error;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    &#125;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="keyword">try</span> &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">      <span class="keyword">const</span> &#123; result &#125; = <span class="keyword">await</span> $UtilsHttp(</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="string">&quot;/passkey/verify-registration&quot;</span>,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="string">&quot;post&quot;</span>,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">          attResp,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">          challenge,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        &#125;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">      );</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">      <span class="keyword">if</span> (result) <span class="title class_">ElMessage</span>.<span class="title function_">success</span>(<span class="string">&quot;已成功添加通行密钥(PassKey)!&quot;</span>);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    &#125; <span class="keyword">catch</span> (error) &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">      <span class="title class_">ElMessage</span>.<span class="title function_">error</span>(error.<span class="property">response</span>.<span class="property">data</span>.<span class="property">error</span>);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    &#125;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  &#125; <span class="keyword">catch</span> (error) &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="title class_">ElMessage</span>.<span class="title function_">error</span>(error.<span class="property">response</span>.<span class="property">data</span>.<span class="property">message</span>);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  &#125;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">&#125;;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="keyword">const</span> <span class="title function_">login</span> = <span class="keyword">async</span> (<span class="params"></span>) =&gt; &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  <span class="keyword">const</span> &#123; result &#125; = <span class="keyword">await</span> $UtilsHttp(</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="string">&quot;/passkey/generate-authentication-options&quot;</span>,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="string">&quot;get&quot;</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  );</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  <span class="keyword">const</span> challenge = result.<span class="property">challenge</span>;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  <span class="keyword">let</span> asseResp;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  <span class="keyword">try</span> &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    asseResp = <span class="keyword">await</span> <span class="title function_">startAuthentication</span>(result);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  &#125; <span class="keyword">catch</span> (error) &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="title class_">ElMessage</span>.<span class="title function_">error</span>(error.<span class="title function_">toString</span>());</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="keyword">throw</span> error;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  &#125;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  <span class="keyword">try</span> &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="keyword">const</span> &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">      <span class="attr">result</span>: &#123; flag, token &#125;,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    &#125; = <span class="keyword">await</span> $UtilsHttp(<span class="string">&quot;/passkey/verify-authentication&quot;</span>, <span class="string">&quot;post&quot;</span>, &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">      asseResp,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">      challenge,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    &#125;);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="keyword">if</span> (flag) <span class="title class_">ElMessage</span>.<span class="title function_">success</span>(<span class="string">&quot;使用通行密钥(PassKey)登录成功!!&quot;</span>);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  &#125; <span class="keyword">catch</span> (error) &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="title class_">ElMessage</span>.<span class="title function_">error</span>(error.<span class="property">response</span>.<span class="property">data</span>.<span class="property">message</span>);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  &#125;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">&#125;;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="title function_">onMounted</span>(<span class="function">() =&gt;</span> &#123;&#125;);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">style</span> <span class="attr">lang</span>=<span class="string">&quot;less&quot;</span> <span class="attr">scoped</span>&gt;</span><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span></span><br><span class="line"></span><br></pre></td></tr></table></figure><h2 id="后端代码"><a href="#后端代码" class="headerlink" title="后端代码"></a>后端代码</h2><h3 id="安装依赖库-1"><a href="#安装依赖库-1" class="headerlink" title="安装依赖库"></a>安装依赖库</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install @simplewebauthn/server</span><br></pre></td></tr></table></figure>]]>
    </content>
    <id>https://blog.zhangsifan.com/posts/20230806pa/</id>
    <link href="https://blog.zhangsifan.com/posts/20230806pa/"/>
    <published>2023-08-05T16:00:00.000Z</published>
    <summary>在 Web 应用中使用表单自动填充功能实现通行密钥</summary>
    <title>通行密钥开发 Passkey</title>
    <updated>2026-03-31T03:22:20.637Z</updated>
  </entry>
  <entry>
    <author>
      <name>JCAlways</name>
    </author>
    <category term="Tauri" scheme="https://blog.zhangsifan.com/tags/Tauri/"/>
    <content>
      <![CDATA[<p><a href="https://tauri.app/zh-cn/">官方网站</a></p><h1 id="Tauri-是什么？"><a href="#Tauri-是什么？" class="headerlink" title="Tauri 是什么？"></a>Tauri 是什么？</h1><p>Tauri 是一个构建适用于所有主流桌面和移动平台的轻快二进制文件的框架。开发者们可以集成任何用于创建用户界面的可以被编译成 HTML、JavaScript 和 CSS 的前端框架，同时可以在必要时使用 Rust、Swift 和 Kotlin 等语言编写后端逻辑。</p><h1 id="前置要求"><a href="#前置要求" class="headerlink" title="前置要求"></a>前置要求</h1><h2 id="系统依赖项"><a href="#系统依赖项" class="headerlink" title="系统依赖项"></a>系统依赖项</h2><h3 id="Windows"><a href="#Windows" class="headerlink" title="Windows"></a>Windows</h3><p>Tauri 使用 Microsoft C++ 构建工具进行开发以及 Microsoft Edge WebView2。这些都是在 Windows 上进行开发所必需的。</p><p>按照以下步骤安装所需的依赖项。</p><h4 id="Microsoft-C-构建工具"><a href="#Microsoft-C-构建工具" class="headerlink" title="Microsoft C++ 构建工具"></a>Microsoft C++ 构建工具</h4><ul><li>下载 <a href="https://visualstudio.microsoft.com/visual-cpp-build-tools/">Microsoft C++</a> 构建工具 安装程序并打开它以开始安装。</li><li>在安装过程中，选中“使用 C++ 进行桌面开发”选项。</li></ul><p><img src="https://tauri.app/_astro/visual-studio-build-tools-installer.TFOm5FVI_RDwYY.webp" alt="Visual Studio C++ 构建工具 安装程序 截图"></p><h4 id="WebView2"><a href="#WebView2" class="headerlink" title="WebView2"></a>WebView2</h4><blockquote><p>WebView 2 已安装在 Windows 10（从版本 1803 开始）和更高版本的 Windows 上。如果你正在这些版本之一上进行开发，则可以跳过此步骤并直接转到 下载并安装 Rust。</p></blockquote><p>Tauri 使用 Microsoft Edge WebView2 在 Windows 上呈现内容。</p><p>通过访问 <a href="https://developer.microsoft.com/zh-cn/microsoft-edge/webview2/#download-section">WebView2 Runtime 下载区</a> 安装 WebView2。下载“常青版独立安装程序（Evergreen Boostrapper）”并安装它。</p><h3 id="MacOS"><a href="#MacOS" class="headerlink" title="MacOS"></a>MacOS</h3><p>Tauri 使用 Xcode 以及各种 macOS 和 iOS 开发依赖项。</p><p>从以下位置之一下载并安装 Xcode：</p><ul><li><a href="https://apps.apple.com/gb/app/xcode/id497799835?mt=12">Mac App Store</a></li><li><a href="https://developer.apple.com/xcode/resources/">Apple Developer 网站</a></li></ul><p>请务必在安装后启动 Xcode，以使它完成设置。</p><h2 id="下载并安装-Rust"><a href="#下载并安装-Rust" class="headerlink" title="下载并安装 Rust"></a>下载并安装 Rust</h2><p>Tauri 使用 Rust 构建并需要它进行开发。使用以下方法之一安装 Rust。你可以在 <a href="https://www.rust-lang.org/tools/install">https://www.rust-lang.org/tools/install</a> 查看更多安装方法。</p><h3 id="Linux-MacOs"><a href="#Linux-MacOs" class="headerlink" title="Linux&#x2F;MacOs"></a>Linux&#x2F;MacOs</h3><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">curl --proto &#x27;=https&#x27; --tlsv1.2 https://sh.rustup.rs -sSf | sh</span><br></pre></td></tr></table></figure><h3 id="Windows-1"><a href="#Windows-1" class="headerlink" title="Windows"></a>Windows</h3><p>前往 <a href="https://www.rust-lang.org/tools/install">https://www.rust-lang.org/tools/install</a> 下载 rustup。</p><p>或者，你可以在 PowerShell 中使用 winget 安装 rustup：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">winget install --id Rustlang.Rustup</span><br></pre></td></tr></table></figure><h1 id="创建项目"><a href="#创建项目" class="headerlink" title="创建项目"></a>创建项目</h1><h2 id="使用-create-tauri-app"><a href="#使用-create-tauri-app" class="headerlink" title="使用 create-tauri-app"></a>使用 create-tauri-app</h2><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm create tauri-app@latest</span><br></pre></td></tr></table></figure><blockquote><p>我们建议从基础模板开始（使用 HTML、CSS 和 JavaScript，不使用前端框架），以便快速入门。随后您可以随时引入前端框架。</p><ul><li>选择您的前端语言：<code>TypeScript / JavaScript</code></li><li>选择您的包管理器：<code>pnpm</code></li><li>选择您的 UI 模板：<code>Vanilla</code></li><li>选择您的 UI 风格：<code>TypeScript</code></li></ul></blockquote><p>在 <code>create-tauri-app</code> 创建完项目后，您可以进入项目文件夹，安装依赖，然后使用 <a href="https://tauri.app/zh-cn/reference/cli/">Tauri CLI</a> 启动开发服务器：</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">cd tauri-app</span><br><span class="line">npm install</span><br><span class="line">npm run tauri dev</span><br></pre></td></tr></table></figure><h1 id="常用功能"><a href="#常用功能" class="headerlink" title="常用功能"></a>常用功能</h1><h2 id="System-Tray-系统托盘"><a href="#System-Tray-系统托盘" class="headerlink" title="System Tray (系统托盘)"></a>System Tray (系统托盘)</h2><p>Tauri 允许您为您的应用程序创建和自定义系统托盘。这可以通过提供对常见操作的快速访问来增强用户体验。</p><h3 id="配置"><a href="#配置" class="headerlink" title="配置"></a>配置</h3><p>首先，更新您的<code>Cargo.toml</code>，以包括系统托盘的必要功能。</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta prompt_"># </span><span class="language-bash">src-tauri/Cargo.toml</span></span><br><span class="line"></span><br><span class="line">tauri = &#123; version = &quot;2.0.0&quot;, features = [ &quot;tray-icon&quot; ] &#125;</span><br></pre></td></tr></table></figure><h3 id="JavsScript-用法"><a href="#JavsScript-用法" class="headerlink" title="JavsScript 用法"></a>JavsScript 用法</h3><h4 id="创建托盘图标"><a href="#创建托盘图标" class="headerlink" title="创建托盘图标"></a>创建托盘图标</h4><p>使用 TrayIcon<a href="https://tauri.app/reference/javascript/api/namespacetray/#new">TrayIcon.new</a>静态功能创建新的托盘图标：</p><figure class="highlight js"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">TrayIcon</span> &#125; <span class="keyword">from</span> <span class="string">&quot;@tauri-apps/api/tray&quot;</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> options = &#123;</span><br><span class="line">  <span class="comment">// here you can add a tray menu, title, tooltip, event handler, etc</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> tray = <span class="keyword">await</span> <span class="title class_">TrayIcon</span>.<span class="title function_">new</span>(options);</span><br></pre></td></tr></table></figure><p>有关自定义选项的更多信息，请参阅<a href="https://tauri.app/reference/javascript/api/namespacetray/#trayiconoptions">TrayIconOptions</a>。</p><h4 id="更改托盘图标"><a href="#更改托盘图标" class="headerlink" title="更改托盘图标"></a>更改托盘图标</h4><p>创建托盘时，您可以使用应用程序图标作为托盘图标：</p><figure class="highlight js"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">TrayIcon</span> &#125; <span class="keyword">from</span> <span class="string">&quot;@tauri-apps/api/tray&quot;</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> options = &#123;</span><br><span class="line">  <span class="attr">icon</span>: <span class="string">&quot;icons/32x32.png&quot;</span>,</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> tray = <span class="keyword">await</span> <span class="title class_">TrayIcon</span>.<span class="title function_">new</span>(options);</span><br></pre></td></tr></table></figure><h4 id="添加菜单和事件"><a href="#添加菜单和事件" class="headerlink" title="添加菜单和事件"></a>添加菜单和事件</h4><p>要附加在点击托盘时显示的菜单，您可以使用 menu 选项。</p><figure class="highlight js"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">TrayIcon</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;@tauri-apps/api/tray&#x27;</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; <span class="title class_">Menu</span> &#125; <span class="keyword">from</span> <span class="string">&#x27;@tauri-apps/api/menu&#x27;</span>;</span><br><span class="line"><span class="keyword">import</span> &#123; getCurrentWindow &#125; <span class="keyword">from</span> <span class="string">&quot;@tauri-apps/api/window&quot;</span>; <span class="comment">// 获取当前窗口</span></span><br><span class="line"><span class="keyword">import</span> &#123; exit &#125; <span class="keyword">from</span> <span class="string">&quot;@tauri-apps/plugin-process&quot;</span>; <span class="comment">// 进程管理</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> menu = <span class="keyword">await</span> <span class="title class_">Menu</span>.<span class="title function_">new</span>(&#123;</span><br><span class="line">    [</span><br><span class="line">      &#123;</span><br><span class="line">        <span class="attr">id</span>: <span class="string">&quot;show&quot;</span>,</span><br><span class="line">        <span class="attr">text</span>: <span class="string">&quot;显示窗口&quot;</span>,</span><br><span class="line">        <span class="attr">action</span>: <span class="function">() =&gt;</span> &#123;</span><br><span class="line">          <span class="title function_">winShowFocus</span>();</span><br><span class="line">        &#125;,</span><br><span class="line">      &#125;,</span><br><span class="line">      &#123;</span><br><span class="line">        <span class="attr">id</span>: <span class="string">&quot;quit&quot;</span>,</span><br><span class="line">        <span class="attr">text</span>: <span class="string">&quot;退出&quot;</span>,</span><br><span class="line">        <span class="attr">action</span>: <span class="function">() =&gt;</span> &#123;</span><br><span class="line">          <span class="title function_">exit</span>(<span class="number">0</span>);</span><br><span class="line">        &#125;,</span><br><span class="line">      &#125;,</span><br><span class="line">    ],</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> options = &#123;</span><br><span class="line">  menu,</span><br><span class="line">  <span class="attr">menuOnLeftClick</span>: <span class="literal">false</span>,</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">winShowFocus</span>(<span class="params"></span>) &#123;</span><br><span class="line">  <span class="keyword">const</span> win = <span class="title function_">getCurrentWindow</span>();</span><br><span class="line">  <span class="keyword">if</span> (!(<span class="keyword">await</span> win.<span class="title function_">isVisible</span>())) &#123;</span><br><span class="line">    win.<span class="title function_">show</span>();</span><br><span class="line">  &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (<span class="keyword">await</span> win.<span class="title function_">isMinimized</span>()) &#123;</span><br><span class="line">      <span class="keyword">await</span> win.<span class="title function_">unminimize</span>();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">await</span> win.<span class="title function_">setFocus</span>();</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> tray = <span class="keyword">await</span> <span class="title class_">TrayIcon</span>.<span class="title function_">new</span>(options);</span><br></pre></td></tr></table></figure><h5 id="显示窗口"><a href="#显示窗口" class="headerlink" title="显示窗口"></a>显示窗口</h5><p><code>tauri</code> 遵循最小权限原则，在运行中可能会碰到如下权限不足的问题：</p><p>在 <code>src-tauri/capabilities/default.json</code> 文件的 <code>permissions</code> 属性数组中加入这几个权限：</p><figure class="highlight json"><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></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;permissions&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">    <span class="string">&quot;core:window:allow-set-focus&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="string">&quot;core:window:allow-close&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="string">&quot;core:window:allow-show&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="string">&quot;core:window:allow-is-visible&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="string">&quot;core:window:allow-unminimize&quot;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="string">&quot;core:window:allow-is-minimized&quot;</span></span><br><span class="line">  <span class="punctuation">]</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><h5 id="退出-重启应用"><a href="#退出-重启应用" class="headerlink" title="退出&#x2F;重启应用"></a>退出&#x2F;重启应用</h5><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm run tauri add process</span><br></pre></td></tr></table></figure><p>引入 API</p><figure class="highlight js"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; exit, relaunch &#125; <span class="keyword">from</span> ‘@tauri-apps/plugin-process’;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 退出应用</span></span><br><span class="line"><span class="keyword">await</span> <span class="title function_">exit</span>(<span class="number">0</span>);</span><br><span class="line"><span class="comment">// 重启应用</span></span><br><span class="line"><span class="keyword">await</span> <span class="title function_">relaunch</span>();</span><br></pre></td></tr></table></figure>]]>
    </content>
    <id>https://blog.zhangsifan.com/posts/20230505tr/</id>
    <link href="https://blog.zhangsifan.com/posts/20230505tr/"/>
    <published>2023-05-04T16:00:00.000Z</published>
    <summary>创建小型、快速、安全、跨平台的应用程序</summary>
    <title>Tauri 2 使用教程</title>
    <updated>2026-03-31T03:22:20.637Z</updated>
  </entry>
  <entry>
    <author>
      <name>JCAlways</name>
    </author>
    <category term="验证类" scheme="https://blog.zhangsifan.com/categories/%E9%AA%8C%E8%AF%81%E7%B1%BB/"/>
    <category term="GeeTest" scheme="https://blog.zhangsifan.com/tags/GeeTest/"/>
    <content>
      <![CDATA[<p><a href="https://www.geetest.com/Sensebot">官方网站</a></p><h1 id="示例"><a href="#示例" class="headerlink" title="示例"></a>示例</h1><script src="https://static.geetest.com/static/js/gt.0.4.9.js"></script><div id="captcha"></div><script>fetch("https://api.zhangsifan.com/geetest/register?").then(async (response) => {  const { result } = await response.json();  console.log(result);  initGeetest(    {      // 以下配置参数来自服务端 SDK      gt: result.gt,      challenge: result.challenge,      offline: !result.success,      new_captcha: true,    },    function (captchaObj) {      captchaObj.appendTo("#captcha");      captchaObj.onSuccess(() => {        var result = captchaObj.getValidate();        console.log(result);        fetch("https://api.zhangsifan.com/geetest/validate", {          method: "POST",          body: JSON.stringify(result),          headers: {            "Content-Type": "application/json",          },        }).then(async (response) => {          const { result } = await response.json();          if (result.success) {            if (window.confirm("验证成功,是否重置验证器?")) {              captchaObj.reset();            }          }        });      });    }  );});</script><h1 id="CodePen-示例"><a href="#CodePen-示例" class="headerlink" title="CodePen 示例"></a>CodePen 示例</h1><iframe height="500" style="width: 100%;" scrolling="no" title="GeeTest3.0使用教程" src="https://codepen.io/AlwaysTeam/embed/pvgyWya?default-tab=js%2Cresult" frameborder="no" loading="lazy" allowtransparency="true" allowfullscreen="true">  See the Pen <a href="https://codepen.io/AlwaysTeam/pen/pvgyWya">  GeeTest3.0使用教程</a> by AlwaysTeam (<a href="https://codepen.io/AlwaysTeam">@AlwaysTeam</a>)  on <a href="https://codepen.io">CodePen</a>.</iframe><h1 id="前端"><a href="#前端" class="headerlink" title="前端"></a>前端</h1><blockquote><p>准备工作：确保已经在极验用户后台获取到了 captchaId</p></blockquote><p><a href="https://docs.geetest.com/sensebot/apirefer/api/web">配置参数</a></p><h2 id="1-引入初始化函数"><a href="#1-引入初始化函数" class="headerlink" title="1.引入初始化函数"></a>1.引入初始化函数</h2><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">&quot;https://static.geetest.com/static/js/gt.0.4.9.js&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure><h2 id="2-初始化"><a href="#2-初始化" class="headerlink" title="2.初始化"></a>2.初始化</h2><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;captcha&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure><figure class="highlight javascript"><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></pre></td><td class="code"><pre><span class="line"><span class="title function_">ajax</span>(&#123;</span><br><span class="line">  <span class="attr">url</span>: <span class="string">&quot;API1接口（详见服务端部署）&quot;</span>,</span><br><span class="line">  <span class="attr">type</span>: <span class="string">&quot;get&quot;</span>,</span><br><span class="line">  <span class="attr">dataType</span>: <span class="string">&quot;json&quot;</span>,</span><br><span class="line">  <span class="attr">success</span>: <span class="keyword">function</span> (<span class="params">data</span>) &#123;</span><br><span class="line">    <span class="comment">//请检测data的数据结构， 保证data.gt, data.challenge, data.success有值</span></span><br><span class="line">    <span class="title function_">initGeetest</span>(</span><br><span class="line">      &#123;</span><br><span class="line">        <span class="comment">// 以下配置参数来自服务端 SDK</span></span><br><span class="line">        <span class="attr">gt</span>: data.<span class="property">gt</span>,</span><br><span class="line">        <span class="attr">challenge</span>: data.<span class="property">challenge</span>,</span><br><span class="line">        <span class="attr">offline</span>: !data.<span class="property">success</span>,</span><br><span class="line">        <span class="attr">new_captcha</span>: <span class="literal">true</span>,</span><br><span class="line">      &#125;,</span><br><span class="line">      <span class="keyword">function</span> (<span class="params">captchaObj</span>) &#123;</span><br><span class="line">        captchaObj.<span class="title function_">appendTo</span>(<span class="string">&quot;#captcha&quot;</span>);</span><br><span class="line">      &#125;</span><br><span class="line">    );</span><br><span class="line">  &#125;,</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><h2 id="3-二次验证"><a href="#3-二次验证" class="headerlink" title="3.二次验证"></a>3.二次验证</h2><figure class="highlight js"><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></pre></td><td class="code"><pre><span class="line"><span class="title function_">initGeetest</span>(</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="comment">// 省略配置参数</span></span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="keyword">function</span> (<span class="params">captchaObj</span>) &#123;</span><br><span class="line">    <span class="comment">// 省略其他方法的调用</span></span><br><span class="line">    captchaObj.<span class="title function_">onSuccess</span>(<span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">      <span class="keyword">var</span> result = captchaObj.<span class="title function_">getValidate</span>();</span><br><span class="line">      <span class="comment">// ajax 伪代码</span></span><br><span class="line">      $.<span class="title function_">ajax</span>(&#123;</span><br><span class="line">        <span class="attr">url</span>: <span class="string">&quot;服务端&quot;</span>,</span><br><span class="line">        <span class="attr">data</span>: result,</span><br><span class="line">        <span class="attr">dataType</span>: <span class="string">&quot;json&quot;</span>,</span><br><span class="line">        <span class="attr">success</span>: <span class="keyword">function</span> (<span class="params">res</span>) &#123;</span><br><span class="line">          <span class="variable language_">console</span>.<span class="title function_">log</span>(res.<span class="property">result</span>);</span><br><span class="line">        &#125;,</span><br><span class="line">      &#125;);</span><br><span class="line">    &#125;);</span><br><span class="line">  &#125;</span><br><span class="line">);</span><br></pre></td></tr></table></figure><h2 id="重置"><a href="#重置" class="headerlink" title="重置"></a>重置</h2><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">captchaObj.<span class="title function_">reset</span>();</span><br></pre></td></tr></table></figure><h1 id="后端"><a href="#后端" class="headerlink" title="后端"></a>后端</h1><blockquote><p>后端使用 Nodejs + Express</p></blockquote><p><a href="https://github.com/GeeTeam/gt3-server-node-express-bypass">官方 Demo</a></p>]]>
    </content>
    <id>https://blog.zhangsifan.com/posts/20230330gt/</id>
    <link href="https://blog.zhangsifan.com/posts/20230330gt/"/>
    <published>2023-03-29T16:00:00.000Z</published>
    <summary>GeeTest3.0使用教程。极验「行为验证」是一项可以帮助你的网站与APP识别与拦截机器程序批量自动化操作的SaaS应用。它是由极验开发的新一代人机验证产品，它不基于传统“问题-答案”的检测模式，而是通过利用深度学习对验证过程中产生的行为数据进行高维分析，发现人机行为模式与行为特征的差异，更加精准地区分人机行为。</summary>
    <title>GeeTest3.0使用教程</title>
    <updated>2026-03-31T03:22:20.637Z</updated>
  </entry>
  <entry>
    <author>
      <name>JCAlways</name>
    </author>
    <category term="验证类" scheme="https://blog.zhangsifan.com/categories/%E9%AA%8C%E8%AF%81%E7%B1%BB/"/>
    <category term="GeeTest" scheme="https://blog.zhangsifan.com/tags/GeeTest/"/>
    <content>
      <![CDATA[<p><a href="https://www.geetest.com/adaptive-captcha-demo">官方网站</a></p><h1 id="示例"><a href="#示例" class="headerlink" title="示例"></a>示例</h1><script src="https://static.geetest.com/v4/gt4.js"></script><div id="captcha"></div><script>initGeetest4(  {    captchaId: "37e44d588298c886c5598e761b83efbb",    nativeButton: {      width: "300px",      height: "40px",    }, // 极验按钮样式设置    userInfo: "user@zhangsifan.com", // 用户信息  },  function (captcha) {    // captcha为验证码实例    captcha.appendTo("#captcha"); // 调用appendTo将验证码插入到页的某一个元素中，这个元素用户可以自定义    captcha.onSuccess(() => {      var result = captcha.getValidate();      fetch("https://api.zhangsifan.com/geetest/validate_v4", {        method: "POST",        body: JSON.stringify(result),        headers: {          "Content-Type": "application/json",        },      }).then(async (response) => {        const { result } = await response.json();        if (result.success) {          if (window.confirm("验证成功,是否重置验证器?")) {            captcha.reset();          }        }      });    });  });</script><h1 id="CodePen-示例"><a href="#CodePen-示例" class="headerlink" title="CodePen 示例"></a>CodePen 示例</h1><iframe height="500" style="width: 100%;" scrolling="no" title="GeeTest4.0使用教程" src="https://codepen.io/AlwaysTeam/embed/VYeaMPY?default-tab=js%2Cresult" frameborder="no" loading="lazy" allowtransparency="true" allowfullscreen="true">  See the Pen <a href="https://codepen.io/AlwaysTeam/pen/VYeaMPY">  GeeTest4.0使用教程</a> by AlwaysTeam (<a href="https://codepen.io/AlwaysTeam">@AlwaysTeam</a>)  on <a href="https://codepen.io">CodePen</a>.</iframe><h1 id="前端"><a href="#前端" class="headerlink" title="前端"></a>前端</h1><blockquote><p>准备工作：确保已经在极验用户后台获取到了 captchaId</p></blockquote><p><a href="https://docs.geetest.com/gt4/apirefer/api/web/#%E9%85%8D%E7%BD%AE%E5%8F%82%E6%95%B0">配置参数</a></p><h2 id="1-引入初始化函数"><a href="#1-引入初始化函数" class="headerlink" title="1.引入初始化函数"></a>1.引入初始化函数</h2><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">&quot;https://static.geetest.com/v4/gt4.js&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure><h2 id="2-初始化"><a href="#2-初始化" class="headerlink" title="2.初始化"></a>2.初始化</h2><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">&quot;captcha&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure><figure class="highlight javascript"><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></pre></td><td class="code"><pre><span class="line"><span class="title function_">initGeetest4</span>(</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="attr">captchaId</span>: <span class="string">&quot;您的captchaId&quot;</span>,</span><br><span class="line">    <span class="attr">nativeButton</span>: &#123;</span><br><span class="line">      <span class="attr">width</span>: <span class="string">&quot;300px&quot;</span>,</span><br><span class="line">      <span class="attr">height</span>: <span class="string">&quot;40px&quot;</span>,</span><br><span class="line">    &#125;, <span class="comment">// 极验按钮样式设置</span></span><br><span class="line">    <span class="attr">userInfo</span>: <span class="string">&quot;user@geetest.com&quot;</span>, <span class="comment">// 用户信息</span></span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="keyword">function</span> (<span class="params">captcha</span>) &#123;</span><br><span class="line">    <span class="comment">// captcha为验证码实例</span></span><br><span class="line">    captcha.<span class="title function_">appendTo</span>(<span class="string">&quot;#captcha&quot;</span>); <span class="comment">// 调用appendTo将验证码插入到页的某一个元素中，这个元素用户可以自定义</span></span><br><span class="line">  &#125;</span><br><span class="line">);</span><br></pre></td></tr></table></figure><h2 id="3-二次验证"><a href="#3-二次验证" class="headerlink" title="3.二次验证"></a>3.二次验证</h2><figure class="highlight js"><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></pre></td><td class="code"><pre><span class="line"><span class="title function_">initGeetest4</span>(</span><br><span class="line">  &#123;</span><br><span class="line">    <span class="comment">// 省略配置参数</span></span><br><span class="line">  &#125;,</span><br><span class="line">  <span class="keyword">function</span> (<span class="params">captchaObj</span>) &#123;</span><br><span class="line">    <span class="comment">// 省略其他方法的调用</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">// 这里调用了 onSuccess 方法，该方法介绍见下文</span></span><br><span class="line">    captchaObj.<span class="title function_">onSuccess</span>(<span class="keyword">function</span> (<span class="params"></span>) &#123;</span><br><span class="line">      <span class="keyword">var</span> result = captchaObj.<span class="title function_">getValidate</span>();</span><br><span class="line"></span><br><span class="line">      <span class="comment">// ajax 伪代码</span></span><br><span class="line">      $.<span class="title function_">ajax</span>(&#123;</span><br><span class="line">        <span class="attr">url</span>: <span class="string">&quot;服务端&quot;</span>,</span><br><span class="line">        <span class="attr">data</span>: result,</span><br><span class="line">        <span class="attr">dataType</span>: <span class="string">&quot;json&quot;</span>,</span><br><span class="line">        <span class="attr">success</span>: <span class="keyword">function</span> (<span class="params">res</span>) &#123;</span><br><span class="line">          <span class="variable language_">console</span>.<span class="title function_">log</span>(res.<span class="property">result</span>);</span><br><span class="line">        &#125;,</span><br><span class="line">      &#125;);</span><br><span class="line">    &#125;);</span><br><span class="line">  &#125;</span><br><span class="line">);</span><br></pre></td></tr></table></figure><h2 id="重置"><a href="#重置" class="headerlink" title="重置"></a>重置</h2><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">captchaObj.<span class="title function_">reset</span>();</span><br></pre></td></tr></table></figure><h1 id="后端"><a href="#后端" class="headerlink" title="后端"></a>后端</h1><blockquote><p>后端使用 Nodejs + Express</p></blockquote><p><a href="https://github.com/GeeTeam/gt4_node_express_demo">官方 Demo</a></p><figure class="highlight js"><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><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> express = <span class="built_in">require</span>(<span class="string">&quot;express&quot;</span>);</span><br><span class="line"><span class="keyword">var</span> querystring = <span class="built_in">require</span>(<span class="string">&quot;querystring&quot;</span>);</span><br><span class="line"><span class="keyword">const</span> crypto = <span class="built_in">require</span>(<span class="string">&quot;crypto&quot;</span>);</span><br><span class="line"><span class="keyword">var</span> axios = <span class="built_in">require</span>(<span class="string">&quot;axios&quot;</span>);</span><br><span class="line"><span class="keyword">var</span> router = express.<span class="title class_">Router</span>();</span><br><span class="line"></span><br><span class="line"><span class="comment">// geetest 公钥</span></span><br><span class="line"><span class="comment">// geetest public key</span></span><br><span class="line"><span class="keyword">const</span> <span class="variable constant_">CAPTCHA_ID</span> = <span class="string">&quot;&quot;</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// geetest 密钥</span></span><br><span class="line"><span class="comment">// geetest secret key</span></span><br><span class="line"><span class="keyword">const</span> <span class="variable constant_">CAPTCHA_KEY</span> = <span class="string">&quot;&quot;</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// geetest 服务地址</span></span><br><span class="line"><span class="comment">// geetest server url</span></span><br><span class="line"><span class="keyword">const</span> <span class="variable constant_">API_SERVER</span> = <span class="string">&quot;http://gcaptcha4.geetest.com&quot;</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// geetest 验证接口</span></span><br><span class="line"><span class="comment">// geetest server interface</span></span><br><span class="line"><span class="keyword">const</span> <span class="variable constant_">API_URL</span> = <span class="variable constant_">API_SERVER</span> + <span class="string">&quot;/validate&quot;</span> + <span class="string">&quot;?captcha_id=&quot;</span> + <span class="variable constant_">CAPTCHA_ID</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* GET home page. */</span></span><br><span class="line">router.<span class="title function_">get</span>(<span class="string">&quot;/&quot;</span>, <span class="keyword">function</span> (<span class="params">req, res, next</span>) &#123;</span><br><span class="line">  res.<span class="title function_">render</span>(<span class="string">&quot;index&quot;</span>);</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line">router.<span class="title function_">get</span>(<span class="string">&quot;/login&quot;</span>, <span class="keyword">function</span> (<span class="params">req, res, next</span>) &#123;</span><br><span class="line">  req.<span class="property">query</span> = querystring.<span class="title function_">parse</span>(req.<span class="property">url</span>.<span class="title function_">split</span>(<span class="string">&quot;?&quot;</span>)[<span class="number">1</span>]);</span><br><span class="line">  <span class="comment">// 前端参数</span></span><br><span class="line">  <span class="comment">// web parameter</span></span><br><span class="line">  <span class="keyword">var</span> lot_number = req.<span class="property">query</span>[<span class="string">&quot;lot_number&quot;</span>];</span><br><span class="line">  <span class="keyword">var</span> captcha_output = req.<span class="property">query</span>[<span class="string">&quot;captcha_output&quot;</span>];</span><br><span class="line">  <span class="keyword">var</span> pass_token = req.<span class="property">query</span>[<span class="string">&quot;pass_token&quot;</span>];</span><br><span class="line">  <span class="keyword">var</span> gen_time = req.<span class="property">query</span>[<span class="string">&quot;gen_time&quot;</span>];</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 生成签名, 使用标准的hmac算法，使用用户当前完成验证的流水号lot_number作为原始消息message，使用客户验证私钥作为key</span></span><br><span class="line">  <span class="comment">// 采用sha256散列算法将message和key进行单向散列生成最终的 “sign_token” 签名</span></span><br><span class="line">  <span class="comment">// use lot_number + CAPTCHA_KEY, generate the signature</span></span><br><span class="line">  <span class="keyword">var</span> sign_token = <span class="title function_">hmac_sha256_encode</span>(lot_number, <span class="variable constant_">CAPTCHA_KEY</span>);</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 向极验转发前端数据 + “sign_token” 签名</span></span><br><span class="line">  <span class="comment">// send web parameter and “sign_token” to geetest server</span></span><br><span class="line">  <span class="keyword">var</span> datas = &#123;</span><br><span class="line">    <span class="attr">lot_number</span>: lot_number,</span><br><span class="line">    <span class="attr">captcha_output</span>: captcha_output,</span><br><span class="line">    <span class="attr">pass_token</span>: pass_token,</span><br><span class="line">    <span class="attr">gen_time</span>: gen_time,</span><br><span class="line">    <span class="attr">sign_token</span>: sign_token,</span><br><span class="line">  &#125;;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// post request</span></span><br><span class="line">  <span class="comment">// 根据极验返回的用户验证状态, 网站主进行自己的业务逻辑</span></span><br><span class="line">  <span class="comment">// According to the user authentication status returned by the geetest, the website owner carries out his own business logic</span></span><br><span class="line">  <span class="title function_">post_form</span>(datas, <span class="variable constant_">API_URL</span>)</span><br><span class="line">    .<span class="title function_">then</span>(<span class="function">(<span class="params">result</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="keyword">if</span> (result[<span class="string">&quot;result&quot;</span>] == <span class="string">&quot;success&quot;</span>) &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;validate success&quot;</span>);</span><br><span class="line">        res.<span class="title function_">send</span>(<span class="string">&quot;success&quot;</span>);</span><br><span class="line">      &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;validate fail:&quot;</span> + result[<span class="string">&quot;reason&quot;</span>]);</span><br><span class="line">        res.<span class="title function_">send</span>(<span class="string">&quot;fail&quot;</span>);</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;)</span><br><span class="line">    .<span class="title function_">catch</span>(<span class="function">(<span class="params">err</span>) =&gt;</span> &#123;</span><br><span class="line">      <span class="comment">// 当请求Geetest服务接口出现异常，应放行通过，以免阻塞正常业务。</span></span><br><span class="line">      <span class="comment">// When the request geetest service interface is abnormal, it shall be released to avoid blocking normal business.</span></span><br><span class="line">      <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;Geetest server error:&quot;</span> + err);</span><br><span class="line">      res.<span class="title function_">send</span>(<span class="string">&quot;success&quot;</span>);</span><br><span class="line">    &#125;);</span><br><span class="line">&#125;);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 生成签名</span></span><br><span class="line"><span class="comment">// Generate signature</span></span><br><span class="line"><span class="keyword">function</span> <span class="title function_">hmac_sha256_encode</span>(<span class="params">value, key</span>) &#123;</span><br><span class="line">  <span class="keyword">var</span> hash = crypto</span><br><span class="line">    .<span class="title function_">createHmac</span>(<span class="string">&quot;sha256&quot;</span>, key)</span><br><span class="line">    .<span class="title function_">update</span>(value, <span class="string">&quot;utf8&quot;</span>)</span><br><span class="line">    .<span class="title function_">digest</span>(<span class="string">&quot;hex&quot;</span>);</span><br><span class="line">  <span class="keyword">return</span> hash;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 发送post请求, 响应json数据如：&#123;&quot;result&quot;: &quot;success&quot;, &quot;reason&quot;: &quot;&quot;, &quot;captcha_args&quot;: &#123;&#125;&#125;</span></span><br><span class="line"><span class="comment">// Send a post request and respond to JSON data, such as: &#123;result &quot;:&quot; success &quot;,&quot; reason &quot;:&quot; &quot;,&quot; captcha_args &quot;: &#123;&#125;&#125;</span></span><br><span class="line"><span class="keyword">async</span> <span class="keyword">function</span> <span class="title function_">post_form</span>(<span class="params">datas, url</span>) &#123;</span><br><span class="line">  <span class="keyword">var</span> options = &#123;</span><br><span class="line">    <span class="attr">url</span>: url,</span><br><span class="line">    <span class="attr">method</span>: <span class="string">&quot;POST&quot;</span>,</span><br><span class="line">    <span class="attr">params</span>: datas,</span><br><span class="line">    <span class="attr">timeout</span>: <span class="number">5000</span>,</span><br><span class="line">  &#125;;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">var</span> result = <span class="keyword">await</span> <span class="title function_">axios</span>(options);</span><br><span class="line"></span><br><span class="line">  <span class="keyword">if</span> (result.<span class="property">status</span> != <span class="number">200</span>) &#123;</span><br><span class="line">    <span class="comment">// geetest服务响应异常</span></span><br><span class="line">    <span class="comment">// geetest service response exception</span></span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="string">&quot;Geetest Response Error, StatusCode:&quot;</span> + result.<span class="property">status</span>);</span><br><span class="line">    <span class="keyword">throw</span> <span class="keyword">new</span> <span class="title class_">Error</span>(<span class="string">&quot;Geetest Response Error&quot;</span>);</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="keyword">return</span> result.<span class="property">data</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="variable language_">module</span>.<span class="property">exports</span> = router;</span><br></pre></td></tr></table></figure>]]>
    </content>
    <id>https://blog.zhangsifan.com/posts/20230329gt/</id>
    <link href="https://blog.zhangsifan.com/posts/20230329gt/"/>
    <published>2023-03-28T16:00:00.000Z</published>
    <summary>GeeTest4.0使用教程。行为验证4.0产品是极验于2022年6月正式推出的最新一代验证码产品，结合环境检测、行为特征、POW工作量证明、视觉模型热更等多项技术，在注册、登录、下单、防作弊等多种场景提供人机智能分流验证服务，为企业安全保驾护航。</summary>
    <title>GeeTest4.0使用教程</title>
    <updated>2026-03-31T03:22:20.637Z</updated>
  </entry>
  <entry>
    <author>
      <name>JCAlways</name>
    </author>
    <category term="Web Office" scheme="https://blog.zhangsifan.com/categories/Web-Office/"/>
    <category term="kkFileViews" scheme="https://blog.zhangsifan.com/tags/kkFileViews/"/>
    <category term="在线预览" scheme="https://blog.zhangsifan.com/tags/%E5%9C%A8%E7%BA%BF%E9%A2%84%E8%A7%88/"/>
    <content>
      <![CDATA[<p><a href="https://kkview.cn/zh-cn/docs/home.html">官方文档</a><br><a href="https://public.zsxq.com/groups/48844125114258.html">KK 开源社区</a></p><h1 id="Docker-容器环境运行"><a href="#Docker-容器环境运行" class="headerlink" title="Docker 容器环境运行"></a>Docker 容器环境运行</h1><figure class="highlight bash"><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></pre></td><td class="code"><pre><span class="line"><span class="comment"># 拉取镜像</span></span><br><span class="line">docker pull keking/kkfileview</span><br><span class="line"><span class="comment"># 运行</span></span><br><span class="line">docker run -it -p 8012:8012 keking/kkfileview</span><br><span class="line"><span class="comment"># 浏览器访问容器8012端口 http://172.0.0.1:8012 即可看到项目演示用首页</span></span><br></pre></td></tr></table></figure><h1 id="源码运行"><a href="#源码运行" class="headerlink" title="源码运行"></a>源码运行</h1><h2 id="1-下载源码"><a href="#1-下载源码" class="headerlink" title="1. 下载源码"></a>1. 下载源码</h2><figure class="highlight bash"><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></pre></td><td class="code"><pre><span class="line"><span class="comment"># gitee</span></span><br><span class="line">https://gitee.com/kekingcn/file-online-preview.git</span><br><span class="line"><span class="comment"># github</span></span><br><span class="line">https://github.com/kekingcn/kkFileView.git</span><br></pre></td></tr></table></figure><h2 id="2-运行"><a href="#2-运行" class="headerlink" title="2. 运行"></a>2. 运行</h2><figure class="highlight bash"><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></pre></td><td class="code"><pre><span class="line"><span class="comment"># 进入 kkFileView 目录</span></span><br><span class="line"><span class="built_in">cd</span> file-online-preview/server/src/main/java/cn.keking/serverMain</span><br><span class="line"><span class="comment"># 运行</span></span><br><span class="line">main</span><br></pre></td></tr></table></figure><h2 id="3-制作Docker镜像"><a href="#3-制作Docker镜像" class="headerlink" title="3. 制作Docker镜像"></a>3. 制作Docker镜像</h2><figure class="highlight bash"><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></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> docker/kkfileview-base</span><br><span class="line">docker build --tag keking/kkfileview-base:4.4.0 .</span><br><span class="line"></span><br><span class="line"><span class="built_in">cd</span> ../..</span><br><span class="line">docker build --tag keking/kkfileview:4.4.0 .</span><br><span class="line"></span><br><span class="line">docker run -d -p 8012:8012 --name kkfileview keking/kkfileview:4.4.0</span><br><span class="line"></span><br><span class="line">docker save -o kkfileview-4.4.0.tar keking/kkfileview:4.4.0</span><br></pre></td></tr></table></figure><h2 id="配置文件"><a href="#配置文件" class="headerlink" title="配置文件"></a>配置文件</h2><p>file-online-preview&#x2F;server&#x2F;src&#x2F;main&#x2F;config&#x2F;application.properties</p><figure class="highlight properties"><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><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">#######################################不可动态配置，需要重启生效#######################################</span></span><br><span class="line"><span class="attr">server.port</span> = <span class="string">$&#123;KK_SERVER_PORT:8012&#125;</span></span><br><span class="line"><span class="attr">server.servlet.context-path</span>= <span class="string">$&#123;KK_CONTEXT_PATH:/&#125;</span></span><br><span class="line"><span class="attr">server.servlet.encoding.charset</span> = <span class="string">utf-8</span></span><br><span class="line"><span class="comment">#启用GZIP压缩功能</span></span><br><span class="line"><span class="attr">server.compression.enabled</span> = <span class="string">true</span></span><br><span class="line"><span class="comment">#允许压缩的响应缓冲区最小字节数，默认2048</span></span><br><span class="line"><span class="attr">server.compression.min-response-size</span> = <span class="string">2048</span></span><br><span class="line"><span class="comment">#压缩格式</span></span><br><span class="line"><span class="attr">server.compression.mime-types</span>=<span class="string">application/javascript,text/css,application/json,application/xml,text/html,text/xml,text/plain,font/woff,application/font-woff,font/eot,image/svg+xml,image/x-icon</span></span><br><span class="line"><span class="comment"># 文件上传限制前端</span></span><br><span class="line"><span class="attr">spring.servlet.multipart.max-file-size</span>=<span class="string">500MB</span></span><br><span class="line"><span class="comment">#文件上传限制</span></span><br><span class="line"><span class="attr">spring.servlet.multipart.max-request-size</span>=<span class="string">500MB</span></span><br><span class="line"><span class="comment">## Freemarker 配置</span></span><br><span class="line"><span class="attr">spring.freemarker.template-loader-path</span> = <span class="string">classpath:/web/</span></span><br><span class="line"><span class="attr">spring.freemarker.cache</span> = <span class="string">false</span></span><br><span class="line"><span class="attr">spring.freemarker.charset</span> = <span class="string">UTF-8</span></span><br><span class="line"><span class="attr">spring.freemarker.check-template-location</span> = <span class="string">true</span></span><br><span class="line"><span class="attr">spring.freemarker.content-type</span> = <span class="string">text/html</span></span><br><span class="line"><span class="attr">spring.freemarker.expose-request-attributes</span> = <span class="string">true</span></span><br><span class="line"><span class="attr">spring.freemarker.expose-session-attributes</span> = <span class="string">true</span></span><br><span class="line"><span class="attr">spring.freemarker.request-context-attribute</span> = <span class="string">request</span></span><br><span class="line"><span class="attr">spring.freemarker.suffix</span> = <span class="string">.ftl</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment"># office设置</span></span><br><span class="line"><span class="comment">#openoffice或LibreOffice  home路径</span></span><br><span class="line"><span class="comment">#office.home = C:\\Program Files (x86)\\OpenOffice 4</span></span><br><span class="line"><span class="attr">office.home</span> = <span class="string">$&#123;KK_OFFICE_HOME:default&#125;</span></span><br><span class="line"><span class="comment">## office转换服务的端口，默认开启两个进程</span></span><br><span class="line"><span class="attr">office.plugin.server.ports</span> = <span class="string">2001,2002</span></span><br><span class="line"><span class="comment">## office 转换服务 task 超时时间，默认五分钟</span></span><br><span class="line"><span class="attr">office.plugin.task.timeout</span> = <span class="string">5m</span></span><br><span class="line"><span class="comment">#此属性设置office进程在重新启动之前可以执行的最大任务数。0表示无限数量的任务（永远不会重新启动）</span></span><br><span class="line"><span class="attr">office.plugin.task.maxtasksperprocess</span> = <span class="string">200</span></span><br><span class="line"><span class="comment">#此属性设置处理任务所允许的最长时间。如果任务的处理时间长于此超时，则此任务将中止，并处理下一个任务。</span></span><br><span class="line"><span class="attr">office.plugin.task.taskexecutiontimeout</span> = <span class="string">5m</span></span><br><span class="line"><span class="comment">#生成限制 默认不限制 使用方法 (1-5)</span></span><br><span class="line"><span class="attr">office.pagerange</span> = <span class="string">$&#123;KK_OFFICE_PAGERANGE:false&#125;</span></span><br><span class="line"><span class="comment">#生成水印 默认不启用 使用方法 (kkFileView)</span></span><br><span class="line"><span class="attr">office.watermark</span>  = <span class="string">$&#123;KK_OFFICE_WATERMARK:false&#125;</span></span><br><span class="line"><span class="comment">#OFFICE JPEG图片压缩</span></span><br><span class="line"><span class="attr">office.quality</span> = <span class="string">$&#123;KK_OFFICE_QUALITY:80&#125;</span></span><br><span class="line"><span class="comment">#图像分辨率限制</span></span><br><span class="line"><span class="attr">office.maximageresolution</span> = <span class="string">$&#123;KK_OFFICE_MAXIMAGERESOLUTION:150&#125;</span></span><br><span class="line"><span class="comment">#导出书签</span></span><br><span class="line"><span class="attr">office.exportbookmarks</span> = <span class="string">$&#123;KK_OFFICE_EXPORTBOOKMARKS:true&#125;</span></span><br><span class="line"><span class="comment">#批注作为PDF的注释</span></span><br><span class="line"><span class="attr">office.exportnotes</span> = <span class="string">$&#123;KK_OFFICE_EXPORTNOTES:true&#125;</span></span><br><span class="line"><span class="comment">#加密文档 生成的PDF文档 添加密码(密码为加密文档的密码)</span></span><br><span class="line"><span class="attr">office.documentopenpasswords</span> = <span class="string">$&#123;KK_OFFICE_DOCUMENTOPENPASSWORD:true&#125;</span></span><br><span class="line"><span class="comment">#xlsx格式前端解析</span></span><br><span class="line"><span class="attr">office.type.web</span> = <span class="string">$&#123;KK_OFFICE_TYPE_WEB:web&#125;</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment"># 其他核心设置</span></span><br><span class="line"><span class="comment">#预览生成资源路径（默认为打包根路径下的file目录下）</span></span><br><span class="line"><span class="comment">#file.dir = D:\\kkFileview\\</span></span><br><span class="line"><span class="attr">file.dir</span> = <span class="string">$&#123;KK_FILE_DIR:default&#125;</span></span><br><span class="line"><span class="comment">#允许预览的本地文件夹 默认不允许任何本地文件被预览</span></span><br><span class="line"><span class="comment">#WINDOWS参考 local.preview.dir =  \D:\\kkFileview\\1\\1.txt (注意前面必须添加反斜杠)</span></span><br><span class="line"><span class="comment">#LINUX参考   local.preview.dir =  /opt/1.txt (注意前面必须是正斜杠)</span></span><br><span class="line"><span class="comment">#使用方法 windows  file://d:/1/1.txt  linux file:/opt/1/1.txt</span></span><br><span class="line"><span class="comment">#file 协议参考：https://datatracker.ietf.org/doc/html/rfc8089</span></span><br><span class="line"><span class="attr">local.preview.dir</span> = <span class="string">$&#123;KK_LOCAL_PREVIEW_DIR:default&#125;</span></span><br><span class="line"><span class="comment">#是否启用缓存</span></span><br><span class="line"><span class="attr">cache.enabled</span> = <span class="string">$&#123;KK_CACHE_ENABLED:true&#125;</span></span><br><span class="line"><span class="comment">#缓存实现类型，不配默认为内嵌RocksDB(type = default)实现，可配置为redis(type = redis)实现（需要配置spring.redisson.address等参数）和 JDK 内置对象实现（type = jdk）,</span></span><br><span class="line"><span class="attr">cache.type</span> =  <span class="string">$&#123;KK_CACHE_TYPE:jdk&#125;</span></span><br><span class="line"><span class="comment">#redis连接，只有当cache.type = redis时才有用</span></span><br><span class="line"><span class="attr">spring.redisson.address</span> = <span class="string">$&#123;KK_SPRING_REDISSON_ADDRESS:127.0.0.1:6379&#125;</span></span><br><span class="line"><span class="attr">spring.redisson.password</span> = <span class="string">$&#123;KK_SPRING_REDISSON_PASSWORD:&#125;</span></span><br><span class="line"><span class="comment">#缓存是否自动清理 true 为开启，注释掉或其他值都为关闭</span></span><br><span class="line"><span class="attr">cache.clean.enabled</span> = <span class="string">$&#123;KK_CACHE_CLEAN_ENABLED:true&#125;</span></span><br><span class="line"><span class="comment">#缓存自动清理时间，cache.clean.enabled = true时才有用，cron表达式，基于Quartz cron</span></span><br><span class="line"><span class="attr">cache.clean.cron</span> = <span class="string">$&#123;KK_CACHE_CLEAN_CRON:0 0 3 * * ?&#125;</span></span><br><span class="line"><span class="comment">#######################################可在运行时动态配置#######################################</span></span><br><span class="line"><span class="comment">#提供预览服务的地址，默认从请求url读，如果使用nginx等反向代理，需要手动设置</span></span><br><span class="line"><span class="comment">#base.url = https://file.keking.cn</span></span><br><span class="line"><span class="attr">base.url</span> = <span class="string">$&#123;KK_BASE_URL:default&#125;</span></span><br><span class="line"><span class="comment">#信任站点，多个用&#x27;,&#x27;隔开，设置了之后，会限制只能预览来自信任站点列表的文件，默认不限制</span></span><br><span class="line"><span class="comment">#trust.host = kkview.cn</span></span><br><span class="line"><span class="attr">trust.host</span> = <span class="string">$&#123;KK_TRUST_HOST:default&#125;</span></span><br><span class="line"><span class="comment">#不信任站点，多个用&#x27;,&#x27;隔开，设置了之后，会限制来自不信任站点列表的文件，默认不限制</span></span><br><span class="line"><span class="comment">#not.trust.host = kkview.cn</span></span><br><span class="line"><span class="attr">not.trust.host</span>= <span class="string">$&#123;KK_NOT_TRUST_HOST:default&#125;</span></span><br><span class="line"><span class="comment">#文本类型，默认如下，可自定义添加</span></span><br><span class="line"><span class="attr">simText</span> = <span class="string">$&#123;KK_SIMTEXT:txt,html,htm,asp,jsp,xml,json,properties,md,gitignore,log,java,py,c,cpp,sql,sh,bat,m,bas,prg,cmd&#125;</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">#FTP模块设置</span></span><br><span class="line"><span class="comment">#预览源为FTP时 FTP用户名，可在ftp url后面加参数ftp.username=ftpuser指定，不指定默认用配置的</span></span><br><span class="line"><span class="attr">ftp.username</span> = <span class="string">$&#123;KK_FTP_USERNAME:ftpuser&#125;</span></span><br><span class="line"><span class="comment">#预览源为FTP时 FTP密码，可在ftp url后面加参数ftp.password=123456指定，不指定默认用配置的</span></span><br><span class="line"><span class="attr">ftp.password</span> = <span class="string">$&#123;KK_FTP_PASSWORD:123456&#125;</span></span><br><span class="line"><span class="comment">#预览源为FTP时, FTP连接默认ControlEncoding(根据FTP服务器操作系统选择，Linux一般为UTF-8，Windows一般为GBK)，可在ftp url后面加参数ftp.control.encoding=UTF-8指定，不指定默认用配置的</span></span><br><span class="line"><span class="attr">ftp.control.encoding</span> = <span class="string">$&#123;KK_FTP_CONTROL_ENCODING:UTF-8&#125;</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">#视频设置</span></span><br><span class="line"><span class="comment">#多媒体类型，默认如下，可自定义添加</span></span><br><span class="line"><span class="attr">media</span> = <span class="string">$&#123;KK_MEDIA:mp3,wav,mp4,flv,mpd,m3u8,ts,mpeg,m4a&#125;</span></span><br><span class="line"><span class="comment">#是否开启多媒体类型转视频格式转换,目前可转换视频格式有：avi,mov,wmv,3gp,rm</span></span><br><span class="line"><span class="comment">#请谨慎开启此功能，建议异步调用添加到处理队列，并且增加任务队列处理线程，防止视频转换占用完线程资源，转换比较耗费时间,并且控制了只能串行处理转换任务</span></span><br><span class="line"><span class="attr">media.convert.disable</span> = <span class="string">$&#123;KK_MEDIA_CONVERT_DISABLE:false&#125;</span></span><br><span class="line"><span class="comment">#支持转换的视频类型</span></span><br><span class="line"><span class="attr">convertMedias</span> = <span class="string">$&#123;KK_CONVERTMEDIAS:avi,mov,wmv,mkv,3gp,rm&#125;</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">#PDF预览模块设置</span></span><br><span class="line"><span class="comment">#配置PDF文件生成图片的像素大小，dpi 越高，图片质量越清晰，同时也会消耗更多的计算资源。</span></span><br><span class="line"><span class="attr">pdf2jpg.dpi</span> = <span class="string">$&#123;KK_PDF2JPG_DPI:144&#125;</span></span><br><span class="line"><span class="comment">#PDF转换超时设置 (低于50页)  温馨提示这里数字仅供参考</span></span><br><span class="line"><span class="attr">pdf.timeout</span> =<span class="string">$&#123;KK_pdf_TIMEOUT:90&#125;</span></span><br><span class="line"><span class="comment">#PDF转换超时设置 (高于50小于200页)</span></span><br><span class="line"><span class="attr">pdf.timeout80</span> =<span class="string">$&#123;KK_PDF_TIMEOUT80:180&#125;</span></span><br><span class="line"><span class="comment">#PDF转换超时设置 (大于200页)</span></span><br><span class="line"><span class="attr">pdf.timeout200</span> =<span class="string">$&#123;KK_PDF_TIMEOUT200:300&#125;</span></span><br><span class="line"><span class="comment">#PDF转换线程设置</span></span><br><span class="line"><span class="attr">pdf.thread</span> =<span class="string">$&#123;KK_PDF_THREAD:5&#125;</span></span><br><span class="line"><span class="comment">#是否禁止演示模式</span></span><br><span class="line"><span class="attr">pdf.presentationMode.disable</span> = <span class="string">$&#123;KK_PDF_PRESENTATION_MODE_DISABLE:true&#125;</span></span><br><span class="line"><span class="comment">#是否禁止打开文件</span></span><br><span class="line"><span class="attr">pdf.openFile.disable</span> = <span class="string">$&#123;KK_PDF_OPEN_FILE_DISABLE:true&#125;</span></span><br><span class="line"><span class="comment">#是否禁止打印转换生成的pdf文件</span></span><br><span class="line"><span class="attr">pdf.print.disable</span> = <span class="string">$&#123;KK_PDF_PRINT_DISABLE:true&#125;</span></span><br><span class="line"><span class="comment">#是否禁止下载转换生成的pdf文件</span></span><br><span class="line"><span class="attr">pdf.download.disable</span> = <span class="string">$&#123;KK_PDF_DOWNLOAD_DISABLE:true&#125;</span></span><br><span class="line"><span class="comment">#是否禁止bookmark</span></span><br><span class="line"><span class="attr">pdf.bookmark.disable</span> = <span class="string">$&#123;KK_PDF_BOOKMARK_DISABLE:true&#125;</span></span><br><span class="line"><span class="comment">#是否禁止签名</span></span><br><span class="line"><span class="attr">pdf.disable.editing</span> = <span class="string">$&#123;KK_PDF_DISABLE_EDITING:false&#125;</span></span><br><span class="line"><span class="comment">#office类型文档(word ppt)样式，默认为图片(image)，可配置为pdf（预览时也有按钮切换）</span></span><br><span class="line"><span class="attr">office.preview.type</span> = <span class="string">$&#123;KK_OFFICE_PREVIEW_TYPE:image&#125;</span></span><br><span class="line"><span class="comment">#是否关闭office预览切换开关，默认为false，可配置为true关闭</span></span><br><span class="line"><span class="attr">office.preview.switch.disabled</span> = <span class="string">$&#123;KK_OFFICE_PREVIEW_SWITCH_DISABLED:false&#125;</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">#水印内容</span></span><br><span class="line"><span class="comment">#例：watermark.txt = $&#123;WATERMARK_TXT:凯京科技内部文件，严禁外泄&#125;</span></span><br><span class="line"><span class="comment">#如需取消水印，内容设置为空即可，例：watermark.txt = $&#123;WATERMARK_TXT:&#125;</span></span><br><span class="line"><span class="attr">watermark.txt</span> = <span class="string">$&#123;WATERMARK_TXT:&#125;</span></span><br><span class="line"><span class="comment">#水印x轴间隔</span></span><br><span class="line"><span class="attr">watermark.x.space</span> = <span class="string">$&#123;WATERMARK_X_SPACE:10&#125;</span></span><br><span class="line"><span class="comment">#水印y轴间隔</span></span><br><span class="line"><span class="attr">watermark.y.space</span> = <span class="string">$&#123;WATERMARK_Y_SPACE:10&#125;</span></span><br><span class="line"><span class="comment">#水印字体</span></span><br><span class="line"><span class="attr">watermark.font</span> = <span class="string">$&#123;WATERMARK_FONT:微软雅黑&#125;</span></span><br><span class="line"><span class="comment">#水印字体大小</span></span><br><span class="line"><span class="attr">watermark.fontsize</span> = <span class="string">$&#123;WATERMARK_FONTSIZE:18px&#125;</span></span><br><span class="line"><span class="comment">#水印字体颜色</span></span><br><span class="line"><span class="attr">watermark.color</span> = <span class="string">$&#123;WATERMARK_COLOR:black&#125;</span></span><br><span class="line"><span class="comment">#水印透明度，要求设置在大于等于0.005，小于1</span></span><br><span class="line"><span class="attr">watermark.alpha</span> = <span class="string">$&#123;WATERMARK_ALPHA:0.2&#125;</span></span><br><span class="line"><span class="comment">#水印宽度</span></span><br><span class="line"><span class="attr">watermark.width</span> = <span class="string">$&#123;WATERMARK_WIDTH:180&#125;</span></span><br><span class="line"><span class="comment">#水印高度</span></span><br><span class="line"><span class="attr">watermark.height</span> = <span class="string">$&#123;WATERMARK_HEIGHT:80&#125;</span></span><br><span class="line"><span class="comment">#水印倾斜度数，要求设置在大于等于0，小于90</span></span><br><span class="line"><span class="attr">watermark.angle</span> = <span class="string">$&#123;WATERMARK_ANGLE:10&#125;</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">#首页功能设置</span></span><br><span class="line"><span class="comment">#是否禁用首页文件上传</span></span><br><span class="line"><span class="attr">file.upload.disable</span> = <span class="string">$&#123;KK_FILE_UPLOAD_DISABLE:true&#125;</span></span><br><span class="line"><span class="comment"># 备案信息，默认为空</span></span><br><span class="line"><span class="attr">beian</span> = <span class="string">$&#123;KK_BEIAN:default&#125;</span></span><br><span class="line"><span class="comment">#禁止上传类型</span></span><br><span class="line"><span class="attr">prohibit</span> = <span class="string">$&#123;KK_PROHIBIT:exe,dll,dat&#125;</span></span><br><span class="line"><span class="comment">#启用验证码删除文件 默认关闭</span></span><br><span class="line"><span class="attr">delete.captcha</span>= <span class="string">$&#123;KK_DELETE_CAPTCHA:false&#125;</span></span><br><span class="line"><span class="comment">#删除密码</span></span><br><span class="line"><span class="attr">delete.password</span> = <span class="string">$&#123;KK_DELETE_PASSWORD:123456&#125;</span></span><br><span class="line"><span class="comment">#删除 转换后OFFICE、CAD、TIFF、压缩包源文件 默认开启 节约磁盘空间</span></span><br><span class="line"><span class="attr">delete.source.file</span> = <span class="string">$&#123;KK_DELETE_SOURCE_FILE:true&#125;</span></span><br><span class="line"><span class="comment">#首页初始化加载第一页</span></span><br><span class="line"><span class="attr">home.pagenumber</span> = <span class="string">$&#123;DEFAULT_HOME_PAGENUMBER:1&#125;</span></span><br><span class="line"><span class="comment">#首页是否分页</span></span><br><span class="line"><span class="attr">home.pagination</span> = <span class="string">$&#123;DEFAULT_HOME_PAGINATION:true&#125;</span></span><br><span class="line"><span class="comment">#首页初始化单页记录数</span></span><br><span class="line"><span class="attr">home.pagesize</span> = <span class="string">$&#123;DEFAULT_HOME_PAGSIZE:15&#125;</span></span><br><span class="line"><span class="comment">#首页显示查询框</span></span><br><span class="line"><span class="attr">home.search</span> = <span class="string">$&#123;DEFAULT_HOME_SEARCH:true&#125;</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">#Tif类型设置</span></span><br><span class="line"><span class="comment">#Tif类型图片浏览模式：tif（利用前端js插件浏览）；jpg（转换为jpg后前端显示）；pdf（转换为pdf后显示，便于打印）</span></span><br><span class="line"><span class="attr">tif.preview.type</span> = <span class="string">$&#123;KK_TIF_PREVIEW_TYPE:tif&#125;</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">#Cad类型设置</span></span><br><span class="line"><span class="comment">#Cad类型图片浏览模式：tif（利用前端js插件浏览）；svg（转换为svg显示）；pdf（转换为pdf后显示，便于打印）</span></span><br><span class="line"><span class="attr">cad.preview.type</span> = <span class="string">$&#123;KK_CAD_PREVIEW_TYPE:svg&#125;</span></span><br><span class="line"><span class="comment">#Cad转换超时设置</span></span><br><span class="line"><span class="attr">cad.timeout</span> =<span class="string">$&#123;KK_CAD_TIMEOUT:90&#125;</span></span><br><span class="line"><span class="comment">#Cad转换线程设置</span></span><br><span class="line"><span class="attr">cad.thread</span> =<span class="string">$&#123;KK_CAD_THREAD:5&#125;</span></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure><h1 id="前端使用"><a href="#前端使用" class="headerlink" title="前端使用"></a>前端使用</h1><figure class="highlight ts"><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></pre></td><td class="code"><pre><span class="line">&lt;script</span><br><span class="line">  <span class="keyword">type</span>=<span class="string">&quot;text/javascript&quot;</span></span><br><span class="line">  src=<span class="string">&quot;https://gcore.jsdelivr.net/npm/js-base64@3.6.0/base64.min.js&quot;</span></span><br><span class="line">&gt;&lt;/script&gt;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> previewUrl = <span class="string">&quot;http://127.0.0.1:8080/file/test.txt&quot;</span>; <span class="comment">//要预览文件的访问地址</span></span><br><span class="line"><span class="variable language_">window</span>.<span class="title function_">open</span>(</span><br><span class="line">  <span class="string">&quot;http://127.0.0.1:8012/onlinePreview?url=&quot;</span> +</span><br><span class="line">    <span class="built_in">encodeURIComponent</span>(<span class="title class_">Base64</span>.<span class="title function_">encode</span>(previewUrl))</span><br><span class="line">);</span><br></pre></td></tr></table></figure><h1 id="常见问题"><a href="#常见问题" class="headerlink" title="常见问题"></a>常见问题</h1><h2 id="预览乱码"><a href="#预览乱码" class="headerlink" title="预览乱码"></a>预览乱码</h2><p>大部分Linux系统上并没有预装中文字体或字体不全，需要把常用字体拷贝到Linux服务器上，具体操作如下： </p><ul><li>下载字体包 <a href="https://kkview.cn/resource/fonts.zip">https://kkview.cn/resource/fonts.zip</a> </li><li>文件解压完整拷贝到Linux下的 <code>/usr/share/fonts</code> 目录。</li><li>然后依次执行以下命令使字体生效<ul><li>mkfontscale</li><li>mkfontdir</li><li>fc-cache</li></ul></li></ul><h1 id="示例"><a href="#示例" class="headerlink" title="示例"></a>示例</h1><iframe src='https://file.kkview.cn' style="width:100%;height:1000px;" frameborder="0"></iframe>]]>
    </content>
    <id>https://blog.zhangsifan.com/posts/20221021ov/</id>
    <link href="https://blog.zhangsifan.com/posts/20221021ov/"/>
    <published>2022-10-20T16:00:00.000Z</published>
    <summary>kkFileView为文件文档在线预览解决方案，该项目使用流行的spring boot搭建，易上手和部署，基本支持主流办公文档的在线预览，如doc,docx,xls,xlsx,ppt,pptx,pdf,txt,zip,rar,图片,视频,音频等等</summary>
    <title>利用 kkFileView 实现在线预览文件</title>
    <updated>2026-03-31T03:22:20.637Z</updated>
  </entry>
  <entry>
    <author>
      <name>JCAlways</name>
    </author>
    <category term="Web Office" scheme="https://blog.zhangsifan.com/categories/Web-Office/"/>
    <category term="WPS Office" scheme="https://blog.zhangsifan.com/tags/WPS-Office/"/>
    <content>
      <![CDATA[<h1 id="相关链接"><a href="#相关链接" class="headerlink" title="相关链接"></a>相关链接</h1><ul><li><a href="https://open.wps.cn/">WPS 开放平台</a></li><li><a href="https://wwo.wps.cn/docs/">WebOffice 文档</a></li><li><a href="https://wwo.wps.cn/docs/update-log/jssdk/">JS-SDK 下载</a></li></ul><h1 id="下载-JS-SDK"><a href="#下载-JS-SDK" class="headerlink" title="下载 JS-SDK"></a>下载 JS-SDK</h1><p>在使用之前，请先下载最新版本的 js-sdk 代码。</p><h1 id="引用-JS-SDK"><a href="#引用-JS-SDK" class="headerlink" title="引用 JS-SDK"></a>引用 JS-SDK</h1><ul><li>非模块化</li></ul><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">&quot;web-office-sdk.umd.js&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure><ul><li>CommonJS 规范</li></ul><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> <span class="title class_">WebOfficeSDK</span> = <span class="built_in">require</span>(<span class="string">&quot;./web-office-sdk.cjs.js&quot;</span>);</span><br></pre></td></tr></table></figure><ul><li>非模块化</li></ul><figure class="highlight ts"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="title class_">WebOfficeSDK</span> <span class="keyword">from</span> <span class="string">&quot;./web-office-sdk.es.js&quot;</span>;</span><br></pre></td></tr></table></figure><h1 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h1><figure class="highlight ts"><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></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  <span class="language-xml"><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;wps&quot;</span>&gt;</span><span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;custom-mount&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line">&lt;/template&gt;</span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">script</span> <span class="attr">setup</span> <span class="attr">lang</span>=<span class="string">&quot;ts&quot;</span>&gt;</span><span class="language-javascript"></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="keyword">import</span> &#123; onMounted &#125; <span class="keyword">from</span> <span class="string">&quot;vue&quot;</span>;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="keyword">import</span> <span class="title class_">WebOfficeSDK</span> <span class="keyword">from</span> <span class="string">&#x27;./web-office-sdk.es.js&#x27;</span>;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="keyword">const</span> <span class="title function_">init</span> = <span class="keyword">async</span> (<span class="params"></span>) =&gt; &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  <span class="keyword">const</span> url = <span class="string">&#x27;&#x27;</span>; <span class="comment">// 后端提供的链接</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  <span class="keyword">const</span> token = <span class="string">&quot;&quot;</span>;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  <span class="keyword">const</span> wps = <span class="title class_">WebOfficeSDK</span>.<span class="title function_">config</span>(&#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="attr">url</span>: url,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="attr">mount</span>: <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&quot;.custom-mount&quot;</span>)!,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  &#125;);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  wps.<span class="title function_">setToken</span>(&#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="attr">token</span>: token,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="attr">timeout</span>: <span class="number">10000</span>,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  &#125;);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">&#125;;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="title function_">onMounted</span>(<span class="function">() =&gt;</span> &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  <span class="title function_">init</span>();</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">&#125;);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">style</span> <span class="attr">lang</span>=<span class="string">&quot;less&quot;</span> <span class="attr">scoped</span>&gt;</span><span class="language-css"></span></span></span><br><span class="line"><span class="language-css"><span class="language-xml"><span class="selector-class">.wps</span> &#123;</span></span></span><br><span class="line"><span class="language-css"><span class="language-xml">  <span class="attribute">width</span>: <span class="number">100%</span>;</span></span></span><br><span class="line"><span class="language-css"><span class="language-xml">  <span class="attribute">height</span>: <span class="number">900px</span>;</span></span></span><br><span class="line"><span class="language-css"><span class="language-xml">  <span class="attribute">background-color</span>: <span class="number">#66ccff</span>;</span></span></span><br><span class="line"><span class="language-css"><span class="language-xml">  <span class="selector-class">.custom-mount</span> &#123;</span></span></span><br><span class="line"><span class="language-css"><span class="language-xml">    <span class="attribute">width</span>: <span class="number">100%</span>;</span></span></span><br><span class="line"><span class="language-css"><span class="language-xml">    <span class="attribute">height</span>: <span class="number">100%</span>;</span></span></span><br><span class="line"><span class="language-css"><span class="language-xml">  &#125;</span></span></span><br><span class="line"><span class="language-css"><span class="language-xml">&#125;</span></span></span><br><span class="line"><span class="language-css"><span class="language-xml"></span><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span></span><br></pre></td></tr></table></figure>]]>
    </content>
    <id>https://blog.zhangsifan.com/posts/20221010bg/</id>
    <link href="https://blog.zhangsifan.com/posts/20221010bg/"/>
    <published>2022-10-09T16:00:00.000Z</published>
    <summary>使用WPS WEB Office,可以在浏览器中打开WPS Office文档,并且可以在线编辑,保存,打印等操作,本文将介绍如何在前端使用WPS WEB Office.</summary>
    <title>WPS WEB Office 前端使用教程</title>
    <updated>2026-03-31T03:22:20.637Z</updated>
  </entry>
  <entry>
    <author>
      <name>JCAlways</name>
    </author>
    <category term="使用文档" scheme="https://blog.zhangsifan.com/categories/%E4%BD%BF%E7%94%A8%E6%96%87%E6%A1%A3/"/>
    <category term="Element Plus" scheme="https://blog.zhangsifan.com/categories/%E4%BD%BF%E7%94%A8%E6%96%87%E6%A1%A3/Element-Plus/"/>
    <category term="文件夹上传" scheme="https://blog.zhangsifan.com/tags/%E6%96%87%E4%BB%B6%E5%A4%B9%E4%B8%8A%E4%BC%A0/"/>
    <content>
      <![CDATA[<h1 id="代码"><a href="#代码" class="headerlink" title="代码"></a>代码</h1><figure class="highlight ts"><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></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  <span class="language-xml"><span class="tag">&lt;<span class="name">el-upload</span></span></span></span><br><span class="line"><span class="tag"><span class="language-xml">    <span class="attr">multiple</span></span></span></span><br><span class="line"><span class="tag"><span class="language-xml">    <span class="attr">action</span>=<span class="string">&quot;http://192.168.1.8:3030/file/upload&quot;</span></span></span></span><br><span class="line"><span class="tag"><span class="language-xml">    <span class="attr">:auto-upload</span>=<span class="string">&quot;false&quot;</span></span></span></span><br><span class="line"><span class="tag"><span class="language-xml">    <span class="attr">:show-file-list</span>=<span class="string">&quot;false&quot;</span></span></span></span><br><span class="line"><span class="tag"><span class="language-xml">    <span class="attr">:on-change</span>=<span class="string">&quot;handleChange&quot;</span></span></span></span><br><span class="line"><span class="tag"><span class="language-xml">  &gt;</span></span></span><br><span class="line"><span class="language-xml">    <span class="tag">&lt;<span class="name">template</span> #<span class="attr">trigger</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">      <span class="tag">&lt;<span class="name">el-button</span> <span class="attr">type</span>=<span class="string">&quot;primary&quot;</span> @<span class="attr">click</span>=<span class="string">&quot;folderMode(false)&quot;</span>&gt;</span>上传文件<span class="tag">&lt;/<span class="name">el-button</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">      <span class="tag">&lt;<span class="name">el-button</span> <span class="attr">type</span>=<span class="string">&quot;primary&quot;</span> @<span class="attr">click</span>=<span class="string">&quot;folderMode(true)&quot;</span>&gt;</span>上传文件夹<span class="tag">&lt;/<span class="name">el-button</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">    <span class="tag">&lt;/<span class="name">template</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">  <span class="tag">&lt;/<span class="name">el-upload</span>&gt;</span></span></span><br><span class="line">&lt;/template&gt;</span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">script</span> <span class="attr">setup</span> <span class="attr">lang</span>=<span class="string">&quot;ts&quot;</span>&gt;</span><span class="language-javascript"></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="keyword">import</span> &#123; reactive, onMounted, nextTick &#125; <span class="keyword">from</span> <span class="string">&quot;vue&quot;</span>;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="keyword">import</span> type &#123; <span class="title class_">UploadFile</span>, <span class="title class_">UploadFiles</span> &#125; <span class="keyword">from</span> <span class="string">&quot;element-plus&quot;</span>;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="keyword">const</span> state = <span class="title function_">reactive</span>(&#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  <span class="attr">uploadEle</span>: <span class="literal">null</span> <span class="keyword">as</span> <span class="title class_">Element</span> | <span class="literal">null</span>,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  <span class="attr">uploadList</span>: [],</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">&#125;);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="keyword">const</span> <span class="title function_">folderMode</span> = (<span class="params">type: boolean</span>) =&gt; &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  <span class="keyword">if</span> (state.<span class="property">uploadEle</span>) &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    state.<span class="property">uploadEle</span>.<span class="property">webkitdirectory</span> = type;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  &#125;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">&#125;;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="keyword">const</span> <span class="title function_">handleChange</span> = <span class="keyword">async</span> (<span class="params"></span></span></span></span><br><span class="line"><span class="params"><span class="language-javascript"><span class="language-xml">  uploadFile: UploadFile,</span></span></span></span><br><span class="line"><span class="params"><span class="language-javascript"><span class="language-xml">  uploadFiles: UploadFiles</span></span></span></span><br><span class="line"><span class="params"><span class="language-javascript"><span class="language-xml"></span>) =&gt; &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  <span class="variable language_">console</span>.<span class="title function_">log</span>(uploadFile, uploadFiles);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">&#125;;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="title function_">onMounted</span>(<span class="function">() =&gt;</span> &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  <span class="title function_">nextTick</span>(<span class="function">() =&gt;</span> &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    state.<span class="property">uploadEle</span> = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&quot;.el-upload__input&quot;</span>);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  &#125;);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">&#125;);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">style</span> <span class="attr">lang</span>=<span class="string">&quot;less&quot;</span> <span class="attr">scoped</span>&gt;</span><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span></span><br></pre></td></tr></table></figure><h1 id="示例"><a href="#示例" class="headerlink" title="示例"></a>示例</h1><iframe src="https://codesandbox.io/p/sandbox/element-upload-n73szt?file=%2Fsrc%2FApp.vue&embed=1"     style="width:100%; height: 800px; border:0; border-radius: 4px; overflow:hidden;"     title="element-upload"     allow="accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking"     sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"   ></iframe>]]>
    </content>
    <id>https://blog.zhangsifan.com/posts/20220915up/</id>
    <link href="https://blog.zhangsifan.com/posts/20220915up/"/>
    <published>2022-09-14T16:00:00.000Z</published>
    <summary>为 El-upload 组件 开启文件夹上传功能</summary>
    <title>El-upload 开启上传文件夹功能</title>
    <updated>2026-03-31T03:22:20.637Z</updated>
  </entry>
  <entry>
    <author>
      <name>JCAlways</name>
    </author>
    <category term="使用文档" scheme="https://blog.zhangsifan.com/categories/%E4%BD%BF%E7%94%A8%E6%96%87%E6%A1%A3/"/>
    <category term="Element Plus" scheme="https://blog.zhangsifan.com/categories/%E4%BD%BF%E7%94%A8%E6%96%87%E6%A1%A3/Element-Plus/"/>
    <category term="Element-Plus" scheme="https://blog.zhangsifan.com/tags/Element-Plus/"/>
    <category term="拖拽" scheme="https://blog.zhangsifan.com/tags/%E6%8B%96%E6%8B%BD/"/>
    <content>
      <![CDATA[<p><a href="https://github.com/SortableJS/vue.draggable.next">官方文档</a></p><h1 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h1><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">yarn add vuedraggable@next</span><br><span class="line"></span><br><span class="line">npm i -S vuedraggable@next</span><br></pre></td></tr></table></figure><h1 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h1><figure class="highlight typescript"><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></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  <span class="language-xml"><span class="tag">&lt;<span class="name">draggable</span></span></span></span><br><span class="line"><span class="tag"><span class="language-xml">    <span class="attr">:list</span>=<span class="string">&quot;state.form_list&quot;</span></span></span></span><br><span class="line"><span class="tag"><span class="language-xml">    <span class="attr">ghost-class</span>=<span class="string">&quot;ghost&quot;</span></span></span></span><br><span class="line"><span class="tag"><span class="language-xml">    <span class="attr">:force-fallback</span>=<span class="string">&quot;true&quot;</span></span></span></span><br><span class="line"><span class="tag"><span class="language-xml">    <span class="attr">chosen-class</span>=<span class="string">&quot;chosenClass&quot;</span></span></span></span><br><span class="line"><span class="tag"><span class="language-xml">    <span class="attr">animation</span>=<span class="string">&quot;200&quot;</span></span></span></span><br><span class="line"><span class="tag"><span class="language-xml">    @<span class="attr">start</span>=<span class="string">&quot;onStart&quot;</span></span></span></span><br><span class="line"><span class="tag"><span class="language-xml">    @<span class="attr">end</span>=<span class="string">&quot;onEnd&quot;</span></span></span></span><br><span class="line"><span class="tag"><span class="language-xml">  &gt;</span></span></span><br><span class="line"><span class="language-xml">    <span class="tag">&lt;<span class="name">template</span> #<span class="attr">item</span>=<span class="string">&quot;&#123; element, index &#125;&quot;</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">      <span class="tag">&lt;<span class="name">div</span> <span class="attr">class</span>=<span class="string">&quot;item_box&quot;</span>&gt;</span>&#123;&#123; element &#125;&#125;&#123;&#123; index &#125;&#125;<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">    <span class="tag">&lt;/<span class="name">template</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">  <span class="tag">&lt;/<span class="name">draggable</span>&gt;</span></span></span><br><span class="line">&lt;/template&gt;</span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">script</span> <span class="attr">setup</span> <span class="attr">lang</span>=<span class="string">&quot;ts&quot;</span>&gt;</span><span class="language-javascript"></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="keyword">import</span> draggable <span class="keyword">from</span> <span class="string">&quot;vuedraggable&quot;</span>;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="keyword">import</span> &#123; reactive, onMounted &#125; <span class="keyword">from</span> <span class="string">&quot;vue&quot;</span>;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="keyword">const</span> state = <span class="title function_">reactive</span>(&#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  <span class="attr">form_list</span>: [&#123; <span class="attr">title</span>: <span class="string">&quot;肯德基&quot;</span> &#125;, &#123; <span class="attr">title</span>: <span class="string">&quot;麦当劳&quot;</span> &#125;],</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">&#125;);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="comment">//开始拖拽事件</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="keyword">const</span> <span class="title function_">onStart</span> = (<span class="params"></span>) =&gt; &#123;&#125;;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="comment">//结束拖拽事件</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="keyword">const</span> <span class="title function_">onEnd</span> = (<span class="params"></span>) =&gt; &#123;&#125;;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="title function_">onMounted</span>(<span class="function">() =&gt;</span> &#123;&#125;);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">style</span> <span class="attr">lang</span>=<span class="string">&quot;less&quot;</span> <span class="attr">scoped</span>&gt;</span><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span></span><br></pre></td></tr></table></figure><h1 id="示例"><a href="#示例" class="headerlink" title="示例"></a>示例</h1><iframe src="https://codesandbox.io/p/sandbox/vue-draggable-4knfkf?file=%2Fsrc%2FApp.vue&embed=1"     style="width:100%; height: 800px; border:0; border-radius: 4px; overflow:hidden;"     title="vue.draggable"     allow="accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking"     sandbox="allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts"   ></iframe>]]>
    </content>
    <id>https://blog.zhangsifan.com/posts/20220909px/</id>
    <link href="https://blog.zhangsifan.com/posts/20220909px/"/>
    <published>2022-09-08T16:00:00.000Z</published>
    <summary>vue.draggable vue3-拖拽排序组件</summary>
    <title>vue.draggable vue3-拖拽排序组件</title>
    <updated>2026-03-31T03:22:20.637Z</updated>
  </entry>
  <entry>
    <author>
      <name>JCAlways</name>
    </author>
    <category term="地图类" scheme="https://blog.zhangsifan.com/categories/%E5%9C%B0%E5%9B%BE%E7%B1%BB/"/>
    <category term="高德地图" scheme="https://blog.zhangsifan.com/tags/%E9%AB%98%E5%BE%B7%E5%9C%B0%E5%9B%BE/"/>
    <content>
      <![CDATA[<p><a href="https://lbs.amap.com/api/jsapi-v2/guide/webcli/map-vue1">官方文档</a></p><h1 id="安装-Loader"><a href="#安装-Loader" class="headerlink" title="安装 Loader"></a>安装 Loader</h1><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm i @amap/amap-jsapi-loader</span><br></pre></td></tr></table></figure><h1 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h1><figure class="highlight typescript"><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"> &lt;!-- <span class="title class_">MyMap</span>.<span class="property">vue</span> --&gt;</span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">template</span>&gt;</span></span></span><br><span class="line"><span class="language-xml">  <span class="tag">&lt;<span class="name">div</span> <span class="attr">:id</span>=<span class="string">&quot;state.id&quot;</span>&gt;</span><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;/<span class="name">template</span>&gt;</span></span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">script</span> <span class="attr">setup</span> <span class="attr">lang</span>=<span class="string">&quot;ts&quot;</span>&gt;</span><span class="language-javascript"></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="keyword">import</span> &#123; onMounted, reactive &#125; <span class="keyword">from</span> <span class="string">&quot;vue&quot;</span>;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="keyword">import</span> <span class="title class_">AMapLoader</span> <span class="keyword">from</span> <span class="string">&quot;@amap/amap-jsapi-loader&quot;</span>;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="keyword">const</span> props = <span class="title function_">defineProps</span>(&#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  <span class="attr">modelValue</span>: <span class="literal">null</span>, <span class="comment">// 坐标</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">&#125;);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="keyword">const</span> state = <span class="title function_">reactive</span>(&#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  <span class="attr">id</span>: <span class="string">&quot;&quot;</span>,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  <span class="attr">map</span>: <span class="literal">null</span> <span class="keyword">as</span> any,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">&#125;);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="keyword">const</span> <span class="title function_">initMap</span> = (<span class="params"></span>) =&gt; &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  state.<span class="property">id</span> =</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="title class_">Math</span>.<span class="title function_">random</span>().<span class="title function_">toString</span>(<span class="number">36</span>).<span class="title function_">substring</span>(<span class="number">7</span>) + <span class="title class_">Math</span>.<span class="title function_">floor</span>(<span class="title class_">Math</span>.<span class="title function_">random</span>() * <span class="number">100</span>);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  <span class="title class_">AMapLoader</span>.<span class="title function_">load</span>(&#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="attr">key</span>: <span class="string">&quot;&quot;</span>, <span class="comment">// 申请好的Web端开发者Key，首次调用 load 时必填</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="attr">version</span>: <span class="string">&quot;2.0&quot;</span>, <span class="comment">// 指定要加载的 JSAPI 的版本</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    <span class="attr">plugins</span>: [<span class="string">&quot;AMap.Scale&quot;</span>, <span class="string">&quot;AMap.Marker&quot;</span>], <span class="comment">// 需要使用的的插件列表</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  &#125;)</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    .<span class="title function_">then</span>(<span class="function">(<span class="params">AMap</span>) =&gt;</span> &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">      state.<span class="property">map</span> = <span class="keyword">new</span> <span class="title class_">AMap</span>.<span class="title class_">Map</span>(state.<span class="property">id</span>, &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="comment">//设置地图容器id</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="attr">viewMode</span>: <span class="string">&quot;3D&quot;</span>, <span class="comment">//是否为3D地图模式</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="attr">zoom</span>: <span class="number">18</span>, <span class="comment">//初始化地图级别</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="attr">center</span>: props.<span class="property">modelValue</span>, <span class="comment">//初始化地图中心点位置</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="attr">doubleClickZoom</span>: <span class="literal">false</span>, <span class="comment">// 禁止双击放大地图</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="attr">layers</span>: [],</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">      &#125;);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">      <span class="keyword">if</span> (state.<span class="property">map</span>) &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="comment">//   比例尺</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="keyword">const</span> scale = <span class="keyword">new</span> <span class="title class_">AMap</span>.<span class="title class_">Scale</span>(&#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">          <span class="attr">visible</span>: <span class="literal">true</span>,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        &#125;);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        state.<span class="property">map</span>.<span class="title function_">addControl</span>(scale);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="comment">// 点</span></span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        <span class="keyword">const</span> marker = <span class="keyword">new</span> <span class="title class_">AMap</span>.<span class="title class_">Marker</span>(&#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">          <span class="attr">position</span>: props.<span class="property">modelValue</span>,</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        &#125;);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">        state.<span class="property">map</span>.<span class="title function_">add</span>(marker);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">      &#125;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    &#125;)</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    .<span class="title function_">catch</span>(<span class="function">(<span class="params">e</span>) =&gt;</span> &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">      <span class="variable language_">console</span>.<span class="title function_">log</span>(e);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">    &#125;);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">&#125;;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"><span class="title function_">onMounted</span>(<span class="function">() =&gt;</span> &#123;</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">  <span class="title function_">initMap</span>();</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml">&#125;);</span></span></span><br><span class="line"><span class="language-javascript"><span class="language-xml"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span></span><br><span class="line"><span class="language-xml"><span class="tag">&lt;<span class="name">style</span> <span class="attr">lang</span>=<span class="string">&quot;less&quot;</span> <span class="attr">scoped</span>&gt;</span><span class="language-css"></span></span></span><br><span class="line"><span class="language-css"><span class="language-xml"><span class="selector-id">#container</span> &#123;</span></span></span><br><span class="line"><span class="language-css"><span class="language-xml">  <span class="attribute">padding</span>: <span class="number">0px</span>;</span></span></span><br><span class="line"><span class="language-css"><span class="language-xml">  <span class="attribute">margin</span>: <span class="number">0px</span>;</span></span></span><br><span class="line"><span class="language-css"><span class="language-xml">  <span class="attribute">width</span>: <span class="number">100%</span>;</span></span></span><br><span class="line"><span class="language-css"><span class="language-xml">  <span class="attribute">height</span>: <span class="number">800px</span>;</span></span></span><br><span class="line"><span class="language-css"><span class="language-xml">&#125;</span></span></span><br><span class="line"><span class="language-css"><span class="language-xml"></span><span class="tag">&lt;/<span class="name">style</span>&gt;</span></span></span><br></pre></td></tr></table></figure>]]>
    </content>
    <id>https://blog.zhangsifan.com/posts/20220905ap/</id>
    <link href="https://blog.zhangsifan.com/posts/20220905ap/"/>
    <published>2022-09-04T16:00:00.000Z</published>
    <summary>Vue3使用高德地图</summary>
    <title>Vue3使用高德地图</title>
    <updated>2026-03-31T03:22:20.637Z</updated>
  </entry>
  <entry>
    <author>
      <name>JCAlways</name>
    </author>
    <category term="验证类" scheme="https://blog.zhangsifan.com/categories/%E9%AA%8C%E8%AF%81%E7%B1%BB/"/>
    <category term="Fingerprintjs" scheme="https://blog.zhangsifan.com/tags/Fingerprintjs/"/>
    <content>
      <![CDATA[<p><a href="https://fingerprint.com/">官方网站</a></p><h1 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h1><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm i @fingerprintjs/fingerprintjs</span><br></pre></td></tr></table></figure><h1 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h1><figure class="highlight typescript"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="title class_">FingerprintJS</span> <span class="keyword">from</span> <span class="string">&quot;@fingerprintjs/fingerprintjs&quot;</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">const</span> <span class="title function_">getFingerPrintID</span> =  <span class="keyword">async</span> (<span class="params"></span>) =&gt; &#123;</span><br><span class="line">    <span class="keyword">const</span> fpPromise = <span class="keyword">await</span> <span class="title class_">FingerprintJS</span>.<span class="title function_">load</span>();</span><br><span class="line">    <span class="keyword">const</span> result = <span class="keyword">await</span> fpPromise.<span class="title function_">get</span>();</span><br><span class="line">    <span class="keyword">return</span> result.<span class="property">visitorId</span>;</span><br><span class="line">&#125;,</span><br><span class="line"></span><br><span class="line"><span class="built_in">setTimeout</span>(<span class="function">() =&gt;</span> &#123;</span><br><span class="line">    <span class="variable language_">console</span>.<span class="title function_">log</span>(<span class="keyword">await</span> <span class="title function_">getFingerPrintID</span>())</span><br><span class="line">&#125;, <span class="number">1000</span>);</span><br></pre></td></tr></table></figure><h1 id="CodePen-示例"><a href="#CodePen-示例" class="headerlink" title="CodePen 示例"></a>CodePen 示例</h1><iframe height="300" style="width: 100%;" scrolling="no" title="Fingerprintjs使用教程" src="https://codepen.io/AlwaysTeam/embed/XWOgZqW?default-tab=js%2Cresult" frameborder="no" loading="lazy" allowtransparency="true" allowfullscreen="true">  See the Pen <a href="https://codepen.io/AlwaysTeam/pen/XWOgZqW">  Fingerprintjs使用教程</a> by AlwaysTeam (<a href="https://codepen.io/AlwaysTeam">@AlwaysTeam</a>)  on <a href="https://codepen.io">CodePen</a>.</iframe>]]>
    </content>
    <id>https://blog.zhangsifan.com/posts/20220903sg/</id>
    <link href="https://blog.zhangsifan.com/posts/20220903sg/"/>
    <published>2022-09-02T16:00:00.000Z</published>
    <summary>Fingerprintjs使用教程</summary>
    <title>Fingerprintjs使用教程</title>
    <updated>2026-03-31T03:22:20.637Z</updated>
  </entry>
  <entry>
    <author>
      <name>JCAlways</name>
    </author>
    <content>
      <![CDATA[<p><a href="https://www.npmjs.com/package/nprogress">官方文档</a></p><h1 id="安装"><a href="#安装" class="headerlink" title="安装"></a>安装</h1><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm install nprogress</span><br></pre></td></tr></table></figure><h1 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h1><figure class="highlight typescript"><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></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> <span class="string">&quot;nprogress/nprogress.css&quot;</span>;</span><br><span class="line"><span class="keyword">import</span> <span class="title class_">NProgress</span> <span class="keyword">from</span> <span class="string">&quot;nprogress&quot;</span>;</span><br><span class="line"><span class="title class_">NProgress</span>.<span class="title function_">configure</span>(&#123; <span class="attr">showSpinner</span>: <span class="literal">false</span> &#125;);</span><br><span class="line"><span class="comment">// 显示进度条</span></span><br><span class="line"><span class="title class_">NProgress</span>.<span class="title function_">start</span>();</span><br><span class="line"><span class="comment">// 隐藏进度条</span></span><br><span class="line"><span class="title class_">NProgress</span>.<span class="title function_">done</span>();</span><br><span class="line"></span><br><span class="line"><span class="title class_">NProgress</span>.<span class="title function_">set</span>(<span class="number">0.0</span>);     <span class="comment">// Sorta same as .start()</span></span><br><span class="line"><span class="title class_">NProgress</span>.<span class="title function_">set</span>(<span class="number">0.4</span>);</span><br><span class="line"><span class="title class_">NProgress</span>.<span class="title function_">set</span>(<span class="number">1.0</span>);     <span class="comment">// Sorta same as .done()</span></span><br></pre></td></tr></table></figure><h1 id="CodePen-示例"><a href="#CodePen-示例" class="headerlink" title="CodePen 示例"></a>CodePen 示例</h1><iframe height="300" style="width: 100%;" scrolling="no" title="nprogress使用教程" src="https://codepen.io/AlwaysTeam/embed/wBKPWWz?default-tab=js%2Cresult&editable=true" frameborder="no" loading="lazy" allowtransparency="true" allowfullscreen="true">  See the Pen <a href="https://codepen.io/AlwaysTeam/pen/wBKPWWz">  nprogress使用教程</a> by AlwaysTeam (<a href="https://codepen.io/AlwaysTeam">@AlwaysTeam</a>)  on <a href="https://codepen.io">CodePen</a>.</iframe>]]>
    </content>
    <id>https://blog.zhangsifan.com/posts/20220903nr/</id>
    <link href="https://blog.zhangsifan.com/posts/20220903nr/"/>
    <published>2022-09-02T16:00:00.000Z</published>
    <summary>Nprogress使用教程</summary>
    <title>Nprogress使用教程</title>
    <updated>2026-03-31T03:22:20.637Z</updated>
  </entry>
</feed>
