http实现文件分片下载

文章目录

    • 检测是否支持
    • HTTP Range 语法
    • Range请求cURL示例
      • 单一范围
      • 多重范围
      • 条件式分片请求
    • Range分片请求的响应
    • 文件整体下载
    • 文件分片下载
      • 文本下载
      • 图片下载
      • 封装下载方法

HTTP分片异步下载是一种下载文件的技术,它允许将一个大文件分成多个小块(分片),然后分别下载这些分片,从而实现更快速、稳定的下载过程。这种技术常用于大文件的下载,例如视频、游戏、软件等。或者与文件下载的断点续传功能搭配使用时非常有用。

比如当你正在看大片时,网络断了,你需要继续看的时候,文件服务器不支持断点的话,则你需要重新等待下载这个大片,才能继续观看。而支持HTTP Range的话,客户端就会记录了之前已经看过的视频文件范围,网络恢复之后,则向服务器发送读取剩余Range的请求,服务端只需要发送客户端请求的那部分内容,而不用整个视频文件发送回客户端,以此节省网络带宽,带来更流畅的用户体验。

检测是否支持

检测服务器端是否支持分片请求。

假如在响应头中存在 Accept-Ranges(并且它的值不为none),那么表示该服务器支持分片请求。例如,你可以使用 cURL 发送一个 HEAD 请求来进行检测。

curl -I https://xxx.jpg

HTTP/1.1 200 OK
...
Accept-Ranges: bytes
Content-Length: 146515

在上面的响应中, Accept-Ranges: bytes 表示界定范围的单位是 bytes。这里 Content-Length 也是有效信息,因为它提供了要检索的图片的完整大小。

如果站点未响应 Accept-Ranges,那么它们有可能不支持分片请求。一些站点会明确将其值设置为 none,以此来表明不支持。在这种情况下,某些应用的下载管理器会将暂停按钮禁用。

curl -I https://xxx.movie

HTTP/1.1 200 OK
...
Accept-Ranges: none

HTTP Range 语法

Range是一个HTTP请求头,告知服务器要返回文件的哪一部分,即:哪个区间范围(字节)的数据。

Range: <unit>=<range-start>-
Range: <unit>=<range-start>-<range-end>
Range: <unit>=<range-start>-<range-end>, <range-start>-<range-end>
Range: <unit>=<range-start>-<range-end>, <range-start>-<range-end>, <range-start>-<range-end>
  • :范围所采用的单位,通常是字节(bytes)

  • :一个整数,表示在特定单位下,范围的起始值。(下标从0开始)

  • :一个整数,表示在特定单位下,范围的结束值。这个值是可选的,如果不存在,表示此范围一直延伸到文档结束。

Range: bytes=200-1000 就是下载 200-1000 字节的内容(两边都是闭区间),服务端返回 206 的状态码,并带上这部分内容。

可以省略右边部分,代表一直到结束:Range: bytes=200-

也可以省略左边部分,代表从头开始:Range: bytes=-1000

而且可以请求多段 range,服务端会返回多段内容:Range: bytes=200-1000, 2000-6576, 19000-

Range请求cURL示例

从服务器端请求特定的范围。

单一范围

我们可以请求资源的某一部分。这次我们依然用 cURL 来进行测试。-H 选项可以在请求中追加一个首部行,在这个例子中,是用 Range 首部来请求图片文件的前 1024 个字节。

curl http://xxx.jpg -i -H "Range: bytes=0-1023"

这样生成的请求如下:

GET /xxx.jpg HTTP/1.1
Host: i.imgur.com
Range: bytes=0-1023

服务器端会返回状态码为 206 Partial Content 的响应:

HTTP/1.1 206 Partial Content
Content-Range: bytes 0-1023/146515
Content-Length: 1024
...
(binary content)

在这里,Content-Length 首部现在用来表示先前请求范围的大小(而不是整张图片的大小)。Content-Range 响应首部则表示这一部分内容在整个资源中所处的位置。

多重范围

Range 头部也支持一次请求文档的多个部分。请求范围用一个逗号分隔开。

curl https://xxx.jpg -i -H "Range: bytes=0-50, 100-150"

服务器返回 206 Partial Content 状态码,Content-Type:multipart/byteranges,boundary=3d6b6a416f9b5 头部。

  • Content-Type:multipart/byteranges 表示这个响应有多个 byterange。
  • 每一部分 byterange 都有他自己的 Content-type 头部和 Content-Range,并且使用 boundary 参数对 body 进行划分。
HTTP/1.1 206 Partial Content
Content-Type: multipart/byteranges; boundary=3d6b6a416f9b5
Content-Length: 282

--3d6b6a416f9b5
Content-Type: text/html
Content-Range: bytes 0-50/1270




    Example Do
--3d6b6a416f9b5
Content-Type: text/html
Content-Range: bytes 100-150/1270

eta http-equiv="Content-type" content="text/html; c
--3d6b6a416f9b5--
</code></pre> 
  <h3>条件式分片请求</h3> 
  <p>当(中断之后)重新开始请求更多资源片段的时候,必须确保自从上一个片段被接收之后该资源没有进行过修改。</p> 
  <p><code>The If-Range</code> 请求首部可以用来生成条件式分片请求:</p> 
  <ul> 
   <li>假如条件满足的话,条件请求就会生效,服务器会返回状态码为 206 Partial 的响应,以及相应的消息主体。</li> 
   <li>假如条件未能得到满足,那么就会返回状态码为 200 OK 的响应,同时返回整个资源。</li> 
  </ul> 
  <p>该首部可以与 <code>Last-Modified</code> 验证器或者 <code>ETag</code> 一起使用,但是二者不能同时使用。</p> 
  <pre><code class="prism language-cmd">If-Range: Wed, 21 Oct 2015 07:28:00 GMT
</code></pre> 
  <h2>Range分片请求的响应</h2> 
  <p>与分片请求相关的有三种状态:</p> 
  <ul> 
   <li>在请求成功的情况下,服务器会返回 <code>206 Partial Content</code> 状态码。请求多个部分,服务器会以 <code>multipart</code> 文件的形式将其返回。</li> 
   <li>在请求的范围越界的情况下(范围值超过了资源的大小),服务器会返回 <code>416 Requested Range Not Satisfiable</code> (请求的范围无法满足)状态码。</li> 
   <li>在不支持分片请求的情况下,服务器会返回 <code>200 OK</code> 状态码。</li> 
  </ul> 
  <h2>文件整体下载</h2> 
  <p>以下实例采用node作为后端。</p> 
  <p>下载文件是一个常见的需求,只要服务端设置 <code>Content-Disposition</code> 为 <code>attachment</code> 就可以。</p> 
  <p>比如这样:</p> 
  <pre><code class="prism language-javascript"><span class="token keyword">const</span> express <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'express'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">const</span> app <span class="token operator">=</span> <span class="token function">express</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

app<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'/download'</span><span class="token punctuation">,</span><span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res<span class="token punctuation">,</span> next</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    res<span class="token punctuation">.</span><span class="token function">setHeader</span><span class="token punctuation">(</span><span class="token string">'Content-Disposition'</span><span class="token punctuation">,</span><span class="token string">'attachment; filename="test.txt"'</span><span class="token punctuation">)</span>
    res<span class="token punctuation">.</span><span class="token function">end</span><span class="token punctuation">(</span><span class="token string">'donwloadfileContent'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>

app<span class="token punctuation">.</span><span class="token function">listen</span><span class="token punctuation">(</span><span class="token number">3000</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">server is running at port 3000</span><span class="token template-punctuation string">`</span></span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre> 
  <p>设置 <code>Cotent-Disposition</code> 为 <code>attachment</code>,指定 <code>filename</code>。</p> 
  <p>然后 html 里加一个 a 标签:</p> 
  <pre><code class="prism language-html"><span class="token doctype"><span class="token punctuation"><!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">html</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>html</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>en<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>body</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>a</span> <span class="token attr-name">href</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>http://localhost:3000/download<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>download<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>a</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>body</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>html</span><span class="token punctuation">></span></span>
</code></pre> 
  <ol> 
   <li>下载<code>http-server</code> npm包,在当前文件目录运行<code>http-server</code>命令跑起静态服务器。</li> 
   <li>点击链接就可以下载。若需要在服务器端js文件修改后动态生效,则可以安装<code>nodemon</code> npm包,进而执行<code>nodemon index.js</code>命令。</li> 
  </ol> 
  <p>当文件过大,则需要对文件进行分片来下载,下面使用案例进行讲解。</p> 
  <h2>文件分片下载</h2> 
  <h3>文本下载</h3> 
  <p>添加这样一个路由:</p> 
  <pre><code class="prism language-javascript">app<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'/downloadRange'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res<span class="token punctuation">,</span> next</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    res<span class="token punctuation">.</span><span class="token function">setHeader</span><span class="token punctuation">(</span><span class="token string">'Access-Control-Allow-Origin'</span><span class="token punctuation">,</span> <span class="token string">'*'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    res<span class="token punctuation">.</span><span class="token function">download</span><span class="token punctuation">(</span><span class="token string">'downloadRange.txt'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
        <span class="token literal-property property">acceptRanges</span><span class="token operator">:</span> <span class="token boolean">true</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre> 
  <p>downloadRange.txt与index.js在同级目录下。</p> 
  <p>设置允许跨域请求,因为前端起的静态服务为http://localhost:8080,而node服务为http://localhost:3000,非同域。</p> 
  <p><code>res.download</code> 是读取文件内容返回,<code>acceptRanges</code> 选项为 true 就是会处理 range 请求(其实默认就是 true)。</p> 
  <p>文件 downloadRange.txt 的内容是这样的:</p> 
  <pre><code class="prism language-txt">0123456789
</code></pre> 
  <p>然后在 html 里访问一下这个接口:</p> 
  <pre><code class="prism language-html"><span class="token doctype"><span class="token punctuation"><!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">html</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>html</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>en<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>body</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript">
        <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">'http://localhost:3000/downloadRange'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
            <span class="token literal-property property">headers</span><span class="token operator">:</span> <span class="token punctuation">{</span>
                <span class="token literal-property property">Range</span><span class="token operator">:</span> <span class="token string">'bytes=0-4'</span><span class="token punctuation">,</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span>
            <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">res</span> <span class="token operator">=></span> res<span class="token punctuation">.</span><span class="token function">text</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
            <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">res</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
                console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>res<span class="token punctuation">)</span> <span class="token comment">// 输出01234</span>
            <span class="token punctuation">}</span><span class="token punctuation">)</span>
            <span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">err</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
                console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span><span class="token punctuation">)</span>
    </span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>body</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>html</span><span class="token punctuation">></span></span>
</code></pre> 
  <p>访问页面,可以看到返回的是 206 的状态码!</p> 
  <p><a href="http://img.e-com-net.com/image/info8/ed267ef9762745789a37cdb60cfa09d0.png" target="_blank"><img src="http://img.e-com-net.com/image/info8/ed267ef9762745789a37cdb60cfa09d0.png" alt="http实现文件分片下载_第1张图片" width="471" height="708" style="border:1px solid black;"></a></p> 
  <p>这时候 <code>Content-Length</code> 就代表返回的内容的长度。</p> 
  <p>还有个 <code>Content-Range</code> 代表当前 range 的长度以及总长度。</p> 
  <p>此时响应内容为01234</p> 
  <p><a href="http://img.e-com-net.com/image/info8/fd32b028778a4db9a59dbaf8cf926fef.png" target="_blank"><img src="http://img.e-com-net.com/image/info8/fd32b028778a4db9a59dbaf8cf926fef.png" alt="" width="481" height="91"></a></p> 
  <p>当然,你也可以访问 5 以后的内容</p> 
  <pre><code class="prism language-javascript"><span class="token literal-property property">Range</span><span class="token operator">:</span> <span class="token string">'bytes=5-'</span>
</code></pre> 
  <p>响应头内容是这样的:</p> 
  <pre><code class="prism language-cmd">Content-Length: 5
Content-Range: bytes 5-9/10
</code></pre> 
  <p>返回的内容是这样的:</p> 
  <pre><code class="prism language-cmd">56789
</code></pre> 
  <p>这俩连接起来就是整个文件的内容。这样就实现了简易版的断点续传。</p> 
  <p>我们再来试试如果超出 range 会怎么样:</p> 
  <pre><code class="prism language-javascript"><span class="token literal-property property">Range</span><span class="token operator">:</span> <span class="token string">'bytes=50-60'</span><span class="token punctuation">,</span>
</code></pre> 
  <p>请求 50-60 字节的内容,这时候响应头是这样的:</p> 
  <pre><code class="prism language-cmd">Status Code: 416 Range Not Satisfiable
</code></pre> 
  <p>返回的是 416 状态码,代表 range 不合法。</p> 
  <p>Range 不是还可以设置多段么?多段内容是怎么返回的呢?</p> 
  <p>我们来试一下:</p> 
  <pre><code class="prism language-javascript"><span class="token literal-property property">Range</span><span class="token operator">:</span> <span class="token string">'bytes=0-1, 3-4, 6-'</span>
</code></pre> 
  <p>重新访问一下,这时候报了一个跨域的错误,说是发送预检请求失败。</p> 
  <pre><code class="prism language-text">Access to fetch at 'http://localhost:3000/downloadRange' from origin 'http://localhost:8080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
</code></pre> 
  <p>浏览器会在三种情况下发送预检(preflight)请求:</p> 
  <ul> 
   <li>用到了非 GET、POST 的请求方法,比如 PUT、DELETE 等,会发预检请求看看服务端是否支持</li> 
   <li>用到了一些非常规请求头,比如用到了 Content-Type,会发预检请求看看服务端是否支持</li> 
   <li>用到了自定义 header,会发预检请求</li> 
  </ul> 
  <p>为啥 Range 头单个 range 不会触发预检请求,而多个 range 就触发了呢?</p> 
  <p>因为多个 range 的时候返回的 Content-Type 是不一样的,是 <code>multipart/byteranges</code> 类型,比较特殊。</p> 
  <p>预检请求是 <code>options</code> 请求,那我们就支持一下:</p> 
  <pre><code class="prism language-javascript">app<span class="token punctuation">.</span><span class="token function">options</span><span class="token punctuation">(</span><span class="token string">'/downloadRange'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res<span class="token punctuation">,</span> next</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    res<span class="token punctuation">.</span><span class="token function">setHeader</span><span class="token punctuation">(</span><span class="token string">'Access-Control-Allow-Origin'</span><span class="token punctuation">,</span> <span class="token string">'*'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    res<span class="token punctuation">.</span><span class="token function">setHeader</span><span class="token punctuation">(</span><span class="token string">'Access-Control-Allow-Headers'</span><span class="token punctuation">,</span> <span class="token string">'Range'</span><span class="token punctuation">)</span>
    res<span class="token punctuation">.</span><span class="token function">end</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> 
  <p>然后重新访问,这时候你会发现虽然状态码为200,且返回的是整个内容!</p> 
  <p>这是因为 express 只做了单 range 的支持,多段 range 可能它觉得没必要支持吧。</p> 
  <p>毕竟你发多个单 range 请求就能达到一样的效果。</p> 
  <h3>图片下载</h3> 
  <p>下面我们就用 range 来实现下文件的分片下载,最终合并成一个文件的功能。</p> 
  <p>我们来下载一个图片吧,分成两块下载,然后下载完合并起来。</p> 
  <p>就用这个图片好了:</p> 
  <p><a href="http://img.e-com-net.com/image/info8/d260975d8478492583619495d789907f.jpg" target="_blank"><img src="http://img.e-com-net.com/image/info8/d260975d8478492583619495d789907f.jpg" alt="http实现文件分片下载_第2张图片" width="650" height="189" style="border:1px solid black;"></a></p> 
  <p>node代码修改如下</p> 
  <pre><code class="prism language-javascript">app<span class="token punctuation">.</span><span class="token function">options</span><span class="token punctuation">(</span><span class="token string">'/downloadPicRange'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res<span class="token punctuation">,</span> next</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    res<span class="token punctuation">.</span><span class="token function">setHeader</span><span class="token punctuation">(</span><span class="token string">'Access-Control-Allow-Origin'</span><span class="token punctuation">,</span> <span class="token string">'*'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    res<span class="token punctuation">.</span><span class="token function">setHeader</span><span class="token punctuation">(</span><span class="token string">'Access-Control-Allow-Headers'</span><span class="token punctuation">,</span> <span class="token string">'Range'</span><span class="token punctuation">)</span>
    res<span class="token punctuation">.</span><span class="token function">end</span><span class="token punctuation">(</span><span class="token string">''</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

app<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'/downloadPicRange'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res<span class="token punctuation">,</span> next</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    res<span class="token punctuation">.</span><span class="token function">setHeader</span><span class="token punctuation">(</span><span class="token string">'Access-Control-Allow-Origin'</span><span class="token punctuation">,</span> <span class="token string">'*'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    res<span class="token punctuation">.</span><span class="token function">download</span><span class="token punctuation">(</span><span class="token string">'1681859964629.png'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
        <span class="token literal-property property">acceptRanges</span><span class="token operator">:</span> <span class="token boolean">true</span>
    <span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre> 
  <p>我们写下分片下载的代码,就分两段:这个图片是 56585 字节,也就是大概55.2k,那我们就分成 0-20000 和 20001- 两段:</p> 
  <pre><code class="prism language-html"><span class="token doctype"><span class="token punctuation"><!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">html</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>html</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>en<span class="token punctuation">"</span></span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"><</span>body</span><span class="token punctuation">></span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>script</span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript">
        <span class="token keyword">const</span> p1 <span class="token operator">=</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">'http://localhost:3000/downloadPicRange'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
            <span class="token literal-property property">headers</span><span class="token operator">:</span> <span class="token punctuation">{</span>
                <span class="token literal-property property">Range</span><span class="token operator">:</span> <span class="token string">'bytes=0-20000'</span><span class="token punctuation">,</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span>
        
        <span class="token keyword">const</span> p2 <span class="token operator">=</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">'http://localhost:3000/downloadPicRange'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
            <span class="token literal-property property">headers</span><span class="token operator">:</span> <span class="token punctuation">{</span>
                <span class="token literal-property property">Range</span><span class="token operator">:</span> <span class="token string">'bytes=20001-'</span><span class="token punctuation">,</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span>

        Promise<span class="token punctuation">.</span><span class="token function">all</span><span class="token punctuation">(</span><span class="token punctuation">[</span>p1<span class="token punctuation">,</span> p2<span class="token punctuation">]</span><span class="token punctuation">)</span>
        <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">res</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
           <span class="token keyword">return</span> Promise<span class="token punctuation">.</span><span class="token function">all</span><span class="token punctuation">(</span>res<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token parameter">resBody</span> <span class="token operator">=></span> resBody<span class="token punctuation">.</span><span class="token function">blob</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span>
        <span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">res</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
            <span class="token keyword">const</span> completeBlob <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Blob</span><span class="token punctuation">(</span>res<span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">type</span><span class="token operator">:</span> res<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>type<span class="token punctuation">}</span><span class="token punctuation">)</span>
            console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>completeBlob<span class="token punctuation">)</span>
            console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token constant">URL</span><span class="token punctuation">.</span><span class="token function">createObjectURL</span><span class="token punctuation">(</span>completeBlob<span class="token punctuation">)</span><span class="token punctuation">)</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span>
        <span class="token punctuation">.</span><span class="token function">catch</span><span class="token punctuation">(</span><span class="token parameter">err</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
            console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>err<span class="token punctuation">)</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span>
    </span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>script</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>body</span><span class="token punctuation">></span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>html</span><span class="token punctuation">></span></span>
</code></pre> 
  <p>两个响应头Content-Range分别是这样的:</p> 
  <pre><code class="prism language-text">Content-Range: bytes 0-20000/56585
</code></pre> 
  <pre><code class="prism language-text">Content-Range: bytes 20001-56584/56585
</code></pre> 
  <p>第一个响应还能看到图片的预览,只能看到上部分:</p> 
  <p></p> 
  <p>然后我们要把两段给拼起来,怎么拼呢?</p> 
  <ol> 
   <li>这里由于使用fetch进行请求,我们可以直接获取响应内容的文件对象为<code>blob</code>类型。</li> 
   <li>然后将两段blob类型文件对象,合并到新的blob文件对象中。</li> 
   <li>通过<code>URL.createObjectURL</code>获取文件对象的资源在本地的链接,将其粘贴到浏览器中,可以看到组合的图片正常显示。</li> 
  </ol> 
  <h3>封装下载方法</h3> 
  <p>当然,一般不会这么写死来用,我们可以封装一个通用的文件分片下载工具。</p> 
  <p>但分片之前需要拿到文件的大小,所以要增加一个接口,调用这个接口返回文件大小:</p> 
  <pre><code class="prism language-javascript"><span class="token keyword">const</span> fs <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'fs'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

app<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">'/length'</span><span class="token punctuation">,</span><span class="token punctuation">(</span><span class="token parameter">req<span class="token punctuation">,</span> res<span class="token punctuation">,</span> next</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
    res<span class="token punctuation">.</span><span class="token function">setHeader</span><span class="token punctuation">(</span><span class="token string">'Access-Control-Allow-Origin'</span><span class="token punctuation">,</span> <span class="token string">'*'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    res<span class="token punctuation">.</span><span class="token function">end</span><span class="token punctuation">(</span><span class="token string">''</span> <span class="token operator">+</span> fs<span class="token punctuation">.</span><span class="token function">statSync</span><span class="token punctuation">(</span><span class="token string">'./1681859964629.png'</span><span class="token punctuation">)</span><span class="token punctuation">.</span>size<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
</code></pre> 
  <p>然后我们来做分片:</p> 
  <pre><code class="prism language-javascript"><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">fileDownloadRange</span><span class="token punctuation">(</span><span class="token parameter">path<span class="token punctuation">,</span> size<span class="token punctuation">,</span> chunkSize</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">let</span> chunkNum <span class="token operator">=</span> Math<span class="token punctuation">.</span><span class="token function">ceil</span><span class="token punctuation">(</span>size <span class="token operator">/</span> chunkSize<span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">const</span> downloadTask <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> i <span class="token operator"><=</span> chunkNum<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">const</span> rangeStart <span class="token operator">=</span> chunkSize <span class="token operator">*</span> <span class="token punctuation">(</span>i <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">const</span> rangeEnd <span class="token operator">=</span> chunkSize <span class="token operator">*</span> i <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">;</span>

        downloadTask<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>
            <span class="token function">fetch</span><span class="token punctuation">(</span>path<span class="token punctuation">,</span> <span class="token punctuation">{</span>
                <span class="token literal-property property">headers</span><span class="token operator">:</span> <span class="token punctuation">{</span>
                    <span class="token literal-property property">Range</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">bytes=</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>rangeStart<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">-</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>rangeEnd<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
                <span class="token punctuation">}</span><span class="token punctuation">,</span>
            <span class="token punctuation">}</span><span class="token punctuation">)</span>
        <span class="token punctuation">)</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">return</span> <span class="token keyword">await</span> Promise<span class="token punctuation">.</span><span class="token function">all</span><span class="token punctuation">(</span>downloadTask<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token parameter">task</span> <span class="token operator">=></span> task<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">res</span> <span class="token operator">=></span> res<span class="token punctuation">.</span><span class="token function">blob</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre> 
  <p>这部分代码不难理解:</p> 
  <p>首先根据 chunk 大小来计算一共几个 chunk,通过 <code>Math.ceil</code> 向上取整。</p> 
  <p>然后计算每个 chunk 的 range,构造下载任务的 promise。</p> 
  <p><code>Promise.all</code> 等待所有下载任务完成,并获取下载内容为<code>blob</code>文件类型</p> 
  <p>我们来验证下:</p> 
  <pre><code class="prism language-javascript"><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">fileDownloadRange</span><span class="token punctuation">(</span><span class="token parameter">path<span class="token punctuation">,</span> size<span class="token punctuation">,</span> chunkSize</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">let</span> chunkNum <span class="token operator">=</span> Math<span class="token punctuation">.</span><span class="token function">ceil</span><span class="token punctuation">(</span>size <span class="token operator">/</span> chunkSize<span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">const</span> downloadTask <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">let</span> i <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span> i <span class="token operator"><=</span> chunkNum<span class="token punctuation">;</span> i<span class="token operator">++</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">const</span> rangeStart <span class="token operator">=</span> chunkSize <span class="token operator">*</span> <span class="token punctuation">(</span>i <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">const</span> rangeEnd <span class="token operator">=</span> chunkSize <span class="token operator">*</span> i <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">;</span>

        downloadTask<span class="token punctuation">.</span><span class="token function">push</span><span class="token punctuation">(</span>
            <span class="token function">fetch</span><span class="token punctuation">(</span>path<span class="token punctuation">,</span> <span class="token punctuation">{</span>
                <span class="token literal-property property">headers</span><span class="token operator">:</span> <span class="token punctuation">{</span>
                    <span class="token literal-property property">Range</span><span class="token operator">:</span> <span class="token template-string"><span class="token template-punctuation string">`</span><span class="token string">bytes=</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>rangeStart<span class="token interpolation-punctuation punctuation">}</span></span><span class="token string">-</span><span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span>rangeEnd<span class="token interpolation-punctuation punctuation">}</span></span><span class="token template-punctuation string">`</span></span><span class="token punctuation">,</span>
                <span class="token punctuation">}</span><span class="token punctuation">,</span>
            <span class="token punctuation">}</span><span class="token punctuation">)</span>
        <span class="token punctuation">)</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">return</span> <span class="token keyword">await</span> Promise<span class="token punctuation">.</span><span class="token function">all</span><span class="token punctuation">(</span>downloadTask<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token parameter">task</span> <span class="token operator">=></span> task<span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">res</span> <span class="token operator">=></span> res<span class="token punctuation">.</span><span class="token function">blob</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>

<span class="token punctuation">(</span><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">const</span> fileLength <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">fetch</span><span class="token punctuation">(</span><span class="token string">'http://localhost:3000/length'</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token parameter">res</span> <span class="token operator">=></span> res<span class="token punctuation">.</span><span class="token function">text</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
    <span class="token keyword">const</span> blobArr <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">fileDownloadRange</span><span class="token punctuation">(</span><span class="token string">'http://localhost:3000/downloadPicRange'</span><span class="token punctuation">,</span> fileLength<span class="token punctuation">,</span> <span class="token number">15000</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">const</span> fileCompleted <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Blob</span><span class="token punctuation">(</span>blobArr<span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">type</span><span class="token operator">:</span> blobArr<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span>type <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token constant">URL</span><span class="token punctuation">.</span><span class="token function">createObjectURL</span><span class="token punctuation">(</span>fileCompleted<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> 
 </div> 
</div>
                            </div>
                        </div>
                    </div>
                    <!--PC和WAP自适应版-->
                    <div id="SOHUCS" sid="1699549036547223552"></div>
                    <script type="text/javascript" src="/views/front/js/chanyan.js"></script>
                    <!-- 文章页-底部 动态广告位 -->
                    <div class="youdao-fixed-ad" id="detail_ad_bottom"></div>
                </div>
                <div class="col-md-3">
                    <div class="row" id="ad">
                        <!-- 文章页-右侧1 动态广告位 -->
                        <div id="right-1" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad">
                            <div class="youdao-fixed-ad" id="detail_ad_1"> </div>
                        </div>
                        <!-- 文章页-右侧2 动态广告位 -->
                        <div id="right-2" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad">
                            <div class="youdao-fixed-ad" id="detail_ad_2"></div>
                        </div>
                        <!-- 文章页-右侧3 动态广告位 -->
                        <div id="right-3" class="col-lg-12 col-md-12 col-sm-4 col-xs-4 ad">
                            <div class="youdao-fixed-ad" id="detail_ad_3"></div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <div class="container">
        <h4 class="pt20 mb15 mt0 border-top">你可能感兴趣的:(HTTP,http,网络协议,网络,前端)</h4>
        <div id="paradigm-article-related">
            <div class="recommend-post mb30">
                <ul class="widget-links">
                    <li><a href="/article/1943993154692771840.htm"
                           title="什么是证书吊销列表?CRL 解释" target="_blank">什么是证书吊销列表?CRL 解释</a>
                        <span class="text-muted">WoTrusSSL</span>
<a class="tag" taget="_blank" href="/search/ssl/1.htm">ssl</a><a class="tag" taget="_blank" href="/search/https/1.htm">https</a>
                        <div>数字证书是安全在线互动的支柱,用于验证身份和确保加密通信。但是,当这些证书被盗用或滥用时,必须立即撤销它们以维持信任。这就是证书撤销列表(CRL)的作用所在。CRL由证书颁发机构(CA)维护,对于识别和撤销已撤销的证书,防止其造成危害至关重要。在本指南中,我们将探讨什么是CRL、它们如何运作以及为什么它们对网络安全至关重要。什么是证书吊销列表(CRL)?证书吊销列表(CRL)是证书颁发机构(CA)</div>
                    </li>
                    <li><a href="/article/1943991135068286976.htm"
                           title="k8s:安装 Helm 私有仓库ChartMuseum、helm-push插件并上传、安装Zookeeper" target="_blank">k8s:安装 Helm 私有仓库ChartMuseum、helm-push插件并上传、安装Zookeeper</a>
                        <span class="text-muted">云游</span>
<a class="tag" taget="_blank" href="/search/docker/1.htm">docker</a><a class="tag" taget="_blank" href="/search/helm/1.htm">helm</a><a class="tag" taget="_blank" href="/search/helm-push/1.htm">helm-push</a>
                        <div>ChartMuseum是Kubernetes生态中用于存储、管理和发布HelmCharts的开源系统,主要用于扩展Helm包管理器的功能核心功能‌集中存储‌:提供中央化仓库存储Charts,支持版本管理和权限控制。‌‌跨集群部署‌:支持多集群环境下共享Charts,简化部署流程。‌‌离线部署‌:适配无网络环境,可将Charts存储在本地或局域网内。‌‌HTTP接口‌:通过HTTP协议提供服务,用户</div>
                    </li>
                    <li><a href="/article/1943990125864218624.htm"
                           title="JavaScript 树形菜单总结" target="_blank">JavaScript 树形菜单总结</a>
                        <span class="text-muted">Auscy</span>
<a class="tag" taget="_blank" href="/search/microsoft/1.htm">microsoft</a>
                        <div>树形菜单是前端开发中常见的交互组件,用于展示具有层级关系的数据(如文件目录、分类列表、组织架构等)。以下从核心概念、实现方式、常见功能及优化方向等方面进行总结。一、核心概念层级结构:数据以父子嵌套形式存在,如{id:1,children:[{id:2}]}。节点:树形结构的基本单元,包含自身信息及子节点(若有)。展开/折叠:子节点的显示与隐藏切换,是树形菜单的核心交互。递归渲染:因数据层级不固定,</div>
                    </li>
                    <li><a href="/article/1943987856808669184.htm"
                           title="前端项目架构设计要领" target="_blank">前端项目架构设计要领</a>
                        <span class="text-muted"></span>

                        <div>1.架构设计的核心目标在设计前端项目架构时,核心目标是模块化、可维护、可扩展、可测试,以及开发效率的最大化。这些目标可以通过以下几个方面来实现:组件化:将UI功能封装为可复用的组件。模块化:将业务逻辑分解为独立的模块或服务。自动化构建与部署:实现自动化构建、测试和部署流程,减少人为操作的错误。代码规范化与检查:确保团队协作时,代码风格和质量一致。2.项目目录结构设计一个清晰合理的目录结构对大型项目</div>
                    </li>
                    <li><a href="/article/1943985463522029568.htm"
                           title="Android 开源组件和第三方库汇总" target="_blank">Android 开源组件和第三方库汇总</a>
                        <span class="text-muted">gyyzzr</span>
<a class="tag" taget="_blank" href="/search/Android/1.htm">Android</a><a class="tag" taget="_blank" href="/search/Android/1.htm">Android</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E6%BA%90%E6%A1%86%E6%9E%B6/1.htm">开源框架</a>
                        <div>转载1、github排名https://github.com/trending,github搜索:https://github.com/search2、https://github.com/wasabeef/awesome-android-ui目录UIUI卫星菜单节选器下拉刷新模糊效果HUD与Toast进度条UI其它动画网络相关响应式编程地图数据库图像浏览及处理视频音频处理测试及调试动态更新热更新</div>
                    </li>
                    <li><a href="/article/1943984830186319872.htm"
                           title="ARM嵌入式可编程控制器技术开发" target="_blank">ARM嵌入式可编程控制器技术开发</a>
                        <span class="text-muted">拉勾科研工作室</span>
<a class="tag" taget="_blank" href="/search/arm%E5%BC%80%E5%8F%91/1.htm">arm开发</a>
                        <div>PLC自动化设计|毕业设计指导|工业自动化解决方案✨专业领域:PLC程序设计与调试工业自动化控制系统HMI人机界面开发工业传感器应用电气控制系统设计工业网络通信擅长工具:西门子S7系列PLC编程三菱/欧姆龙PLC应用触摸屏界面设计电气CAD制图工业现场总线技术自动化设备调试主要内容:PLC控制系统设计工业自动化方案规划电气原理图绘制控制程序编写与调试毕业论文指导毕业设计题目与程序设计✅具体问题可以</div>
                    </li>
                    <li><a href="/article/1943984451734269952.htm"
                           title="理解TCP连接中的进程阻塞与CPU调度机制" target="_blank">理解TCP连接中的进程阻塞与CPU调度机制</a>
                        <span class="text-muted">109702008</span>
<a class="tag" taget="_blank" href="/search/%E7%BC%96%E7%A8%8B/1.htm">编程</a><a class="tag" taget="_blank" href="/search/%23/1.htm">#</a><a class="tag" taget="_blank" href="/search/C%E8%AF%AD%E8%A8%80/1.htm">C语言</a><a class="tag" taget="_blank" href="/search/%E7%BD%91%E7%BB%9C/1.htm">网络</a><a class="tag" taget="_blank" href="/search/tcp%2Fip/1.htm">tcp/ip</a><a class="tag" taget="_blank" href="/search/%E7%BD%91%E7%BB%9C/1.htm">网络</a><a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a>
                        <div>引言在计算机网络通信中,TCP连接的建立是一个经典的三次握手过程。当用户调用connect()函数发起连接时,内核会发送SYN报文并等待对方的SYN-ACK响应。此时,调用进程通常会进入阻塞状态,暂停执行直至连接成功或超时。这一机制看似简单,但其背后的内核实现却涉及进程调度、等待队列管理和CPU资源分配等复杂操作。本文将深入探讨阻塞状态的实现原理,并解析CPU在进程阻塞期间的行为。一、进程阻塞的实</div>
                    </li>
                    <li><a href="/article/1943983696184930304.htm"
                           title="基于链家网的二手房数据采集清洗与可视化分析" target="_blank">基于链家网的二手房数据采集清洗与可视化分析</a>
                        <span class="text-muted">Mint_Datazzh</span>
<a class="tag" taget="_blank" href="/search/%E9%A1%B9%E7%9B%AE/1.htm">项目</a><a class="tag" taget="_blank" href="/search/selenium/1.htm">selenium</a><a class="tag" taget="_blank" href="/search/%E7%BD%91%E7%BB%9C%E7%88%AC%E8%99%AB/1.htm">网络爬虫</a>
                        <div>个人学习内容笔记,仅供参考。项目链接:https://gitee.com/rongwu651/lianjia原文链接:基于链家网的二手房数据采集清洗与可视化分析–笔墨云烟研究内容该课题的主要目的是通过将二手房网站上的存量与已销售房源,构建一个二手房市场行情情况与房源特点的可视化平台。该平台通过HTML架构和Echarts完成可视化的搭建。因此,该课题的主要研究内容就是如何利用相关技术设计并实现这样</div>
                    </li>
                    <li><a href="/article/1943982937041072128.htm"
                           title="2025代码块种类以及作用" target="_blank">2025代码块种类以及作用</a>
                        <span class="text-muted">2501_92758067</span>
<a class="tag" taget="_blank" href="/search/intellij-idea/1.htm">intellij-idea</a><a class="tag" taget="_blank" href="/search/phpstorm/1.htm">phpstorm</a><a class="tag" taget="_blank" href="/search/idea/1.htm">idea</a><a class="tag" taget="_blank" href="/search/jupyter/1.htm">jupyter</a>
                        <div>https://www.bilibili.com/opus/1088624478422827030https://www.bilibili.com/opus/1088624529930977287https://t.bilibili.com/1088633635294150662https://www.bilibili.com/opus/1088633635294150662https://t.b</div>
                    </li>
                    <li><a href="/article/1943979785097113600.htm"
                           title="【前端】jQuery数组合并去重方法总结" target="_blank">【前端】jQuery数组合并去重方法总结</a>
                        <span class="text-muted"></span>

                        <div>在jQuery中合并多个数组并去重,推荐使用原生JavaScript的Set对象(高效简单)或$.unique()(仅适用于DOM元素,不适用于普通数组)。以下是完整解决方案:方法1:使用ES6Set(推荐)//定义多个数组constarr1=[1,2,3];constarr2=[2,3,4];constarr3=[3,4,5];//合并数组并用Set去重constmergedArray=[...</div>
                    </li>
                    <li><a href="/article/1943978399890468864.htm"
                           title="如何解决 NPM proxy, 当我们在终端nodejs应用程序时出现代理相关报错" target="_blank">如何解决 NPM proxy, 当我们在终端nodejs应用程序时出现代理相关报错</a>
                        <span class="text-muted"></span>

                        <div>Thisisaproblemrelatedtonetworkconnectivity.npmERR!networkInmostcasesyouarebehindaproxyorhavebadnetworksettings.在使用npminstall下载包的时候总是报以下错误:在控制台或VisualStudioCode终端中运行以下命令:npmconfigrmproxynpmconfigrmhttp</div>
                    </li>
                    <li><a href="/article/1943975880120397824.htm"
                           title="php SPOF" target="_blank">php SPOF</a>
                        <span class="text-muted">贵哥的编程之路(热爱分享 为后来者)</span>
<a class="tag" taget="_blank" href="/search/PHP%E8%AF%AD%E8%A8%80%E7%BB%8F%E5%85%B8%E7%A8%8B%E5%BA%8F100%E9%A2%98/1.htm">PHP语言经典程序100题</a><a class="tag" taget="_blank" href="/search/php/1.htm">php</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a>
                        <div>1.什么是单点故障(SPOF)?单点故障指的是系统中某个组件一旦失效,整个系统或服务就会不可用。常见的单点有:数据库、缓存、Web服务器、负载均衡、网络设备等。2.常见单点故障场景只有一台数据库服务器,宕机后所有业务不可用只有一台Redis缓存,挂掉后缓存全部失效只有一台Web服务器,挂掉后网站无法访问只有一个负载均衡节点,挂掉后流量无法分发只有一条网络链路,断开后所有服务失联3.消除单点故障的主</div>
                    </li>
                    <li><a href="/article/1943974618851241984.htm"
                           title="Vue3+Vite+TS+Axios整合详细教程" target="_blank">Vue3+Vite+TS+Axios整合详细教程</a>
                        <span class="text-muted">老马聊技术</span>
<a class="tag" taget="_blank" href="/search/Vue/1.htm">Vue</a><a class="tag" taget="_blank" href="/search/Vite/1.htm">Vite</a><a class="tag" taget="_blank" href="/search/TS/1.htm">TS</a><a class="tag" taget="_blank" href="/search/vue.js/1.htm">vue.js</a>
                        <div>1.Vite简介Vite是新一代的前端构建工具,在尤雨溪开发Vue3.0的时候诞生。类似于Webpack+Webpack-dev-server。其主要利用浏览器ESM特性导入组织代码,在服务器端按需编译返回,完全跳过了打包这个概念,服务器随起随用。生产中利用Rollup作为打包工具,号称下一代的前端构建工具。vite是一种新型的前端构建工具,能够显著的提升前端开发者的体验。它主要有俩部分组成:一个</div>
                    </li>
                    <li><a href="/article/1943973484015185920.htm"
                           title="npm proxy setting" target="_blank">npm proxy setting</a>
                        <span class="text-muted">kjndppl</span>
<a class="tag" taget="_blank" href="/search/%5BNode.js/1.htm">[Node.js</a><a class="tag" taget="_blank" href="/search/JavaScript/1.htm">JavaScript</a><a class="tag" taget="_blank" href="/search/npm/1.htm">npm</a><a class="tag" taget="_blank" href="/search/https/1.htm">https</a><a class="tag" taget="_blank" href="/search/proxy/1.htm">proxy</a><a class="tag" taget="_blank" href="/search/password/1.htm">password</a>
                        <div>清理npmconfigdeletehttp-proxynpmconfigdeletehttps-proxy具体设置步骤如下:1.执行npmconfig后,将看到下一行提示信息npmconfigls-ltoshowalldefaults.2.执行npmconfigls-l后,在一大长串的settign中找出userconfig项(大概位于倒数第4项)[b]userconfig[/b]="C:\\Us</div>
                    </li>
                    <li><a href="/article/1943971716690669568.htm"
                           title="windows安装pnpm后报错:pnpm : 无法将“pnpm”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。" target="_blank">windows安装pnpm后报错:pnpm : 无法将“pnpm”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。</a>
                        <span class="text-muted">Ithao2</span>
<a class="tag" taget="_blank" href="/search/Vue/1.htm">Vue</a><a class="tag" taget="_blank" href="/search/npm/1.htm">npm</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/node.js/1.htm">node.js</a>
                        <div>使用npm方式安装pnpm,命令如下:npminstall-gpnpm安装完以后,执行pnpm-v查看版本号:pnpm-v执行完发现报错:pnpm:无法将“pnpm”项识别为cmdlet、函数、脚本文件或可运行程序的名称。尝试配置环境变量,重启后均不生效。解决方案:使用PowerShell进行安装1.以管理员用户打开PowerShell,执行如下命令:iwrhttps://get.pnpm.io/</div>
                    </li>
                    <li><a href="/article/1943971211121848320.htm"
                           title="前端 NPM 包的依赖可视化分析工具推荐" target="_blank">前端 NPM 包的依赖可视化分析工具推荐</a>
                        <span class="text-muted">前端视界</span>
<a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF%E8%89%BA%E5%8C%A0%E9%A6%86/1.htm">前端艺匠馆</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/npm/1.htm">npm</a><a class="tag" taget="_blank" href="/search/arcgis/1.htm">arcgis</a><a class="tag" taget="_blank" href="/search/ai/1.htm">ai</a>
                        <div>前端NPM包的依赖可视化分析工具推荐关键词:NPM、依赖管理、可视化分析、前端工程、包管理、依赖冲突、性能优化摘要:本文将深入探讨前端开发中NPM包依赖可视化分析的重要性,介绍5款主流工具的使用方法和特点,并通过实际案例展示如何利用这些工具优化项目依赖结构、解决版本冲突问题以及提升构建性能。文章将帮助开发者更好地理解和掌控项目依赖关系,提高开发效率和项目可维护性。背景介绍目的和范围本文旨在为前端开</div>
                    </li>
                    <li><a href="/article/1943971212849901568.htm"
                           title="计算机网络技术" target="_blank">计算机网络技术</a>
                        <span class="text-muted">CZZDg</span>
<a class="tag" taget="_blank" href="/search/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C/1.htm">计算机网络</a>
                        <div>目录一.网络概述1.网络的概念2.网络发展是3.网络的四要素4.网络功能5.网络类型6.网络协议与标准7.网络中常见的概念8.网络拓补结构二.网络模型1.分层思想2.OSI七层模型3.TCP/IP五层模型4.数据的封装与解封装过程三.IP地址1.进制转换2.IP地址定义3.IP地址组成成分4.IP地址分类5.地址划分6、相关概念一.网络概述1.网络的概念两个主机通过传输介质和通信协议实现通信和资源</div>
                    </li>
                    <li><a href="/article/1943969069501837312.htm"
                           title="EasyCwmp源码分析与接口实现详解:深入理解源码架构,掌握核心接口" target="_blank">EasyCwmp源码分析与接口实现详解:深入理解源码架构,掌握核心接口</a>
                        <span class="text-muted"></span>

                        <div>EasyCwmp源码分析与接口实现详解:深入理解源码架构,掌握核心接口去发现同类优质开源项目:https://gitcode.com/在开源项目中,寻找一款能够提升开发效率、简化流程的工具是每个开发者的追求。今天,我们要介绍的这款开源项目EasyCwmp,正是为了帮助开发者深入了解源码架构,掌握核心接口实现,从而加速项目开发进程。以下是关于EasyCwmp源码分析与接口实现详解的项目推荐文章。项目</div>
                    </li>
                    <li><a href="/article/1943967555555225600.htm"
                           title="基于Python的健身数据分析工具的搭建流程day1" target="_blank">基于Python的健身数据分析工具的搭建流程day1</a>
                        <span class="text-muted">weixin_45677320</span>
<a class="tag" taget="_blank" href="/search/python/1.htm">python</a><a class="tag" taget="_blank" href="/search/%E5%BC%80%E5%8F%91%E8%AF%AD%E8%A8%80/1.htm">开发语言</a><a class="tag" taget="_blank" href="/search/%E6%95%B0%E6%8D%AE%E6%8C%96%E6%8E%98/1.htm">数据挖掘</a><a class="tag" taget="_blank" href="/search/%E7%88%AC%E8%99%AB/1.htm">爬虫</a>
                        <div>基于Python的健身数据分析工具的搭建流程分数据挖掘、数据存储和数据分析三个步骤。本文主要介绍利用Python实现健身数据分析工具的数据挖掘部分。第一步:加载库加载本文需要的库,如下代码所示。若库未安装,请按照python如何安装各种库(保姆级教程)_python安装库-CSDN博客https://blog.csdn.net/aobulaien001/article/details/133298</div>
                    </li>
                    <li><a href="/article/1943967429147291648.htm"
                           title="tcpdump交叉编译" target="_blank">tcpdump交叉编译</a>
                        <span class="text-muted">weixin_45673259</span>
<a class="tag" taget="_blank" href="/search/tcpdump/1.htm">tcpdump</a><a class="tag" taget="_blank" href="/search/%E6%B5%8B%E8%AF%95%E5%B7%A5%E5%85%B7/1.htm">测试工具</a><a class="tag" taget="_blank" href="/search/%E7%BD%91%E7%BB%9C/1.htm">网络</a>
                        <div>1.下载路径官网:https://www.tcpdump.org/2.编译解压:tar-xflibpcap-1.10.4.tar.xztar-xftcpdump-4.99.4.tar.xz编译libpcap./configure--host=mips-v720s229-linux--target=mips-v720s229-linuxCC=/opt/A1/mips-gcc720-uclibc229</div>
                    </li>
                    <li><a href="/article/1943963649831923712.htm"
                           title="玩转Docker | 使用Docker部署gopeed下载工具" target="_blank">玩转Docker | 使用Docker部署gopeed下载工具</a>
                        <span class="text-muted">心随_风动</span>
<a class="tag" taget="_blank" href="/search/%E7%8E%A9%E8%BD%ACDocker/1.htm">玩转Docker</a><a class="tag" taget="_blank" href="/search/docker/1.htm">docker</a><a class="tag" taget="_blank" href="/search/%E5%AE%B9%E5%99%A8/1.htm">容器</a><a class="tag" taget="_blank" href="/search/%E8%BF%90%E7%BB%B4/1.htm">运维</a>
                        <div>玩转Docker|使用Docker部署gopeed下载工具前言一、gopeed介绍Gopeed简介主要特点二、系统要求环境要求环境检查Docker版本检查检查操作系统版本三、部署gopeed服务下载镜像创建容器检查容器状态检查服务端口安全设置四、访问gopeed应用五、测试与下载六、总结前言在当今信息爆炸的时代,高效地获取和管理网络资源变得尤为重要。无论是下载大型文件还是进行日常的数据传输,一个稳</div>
                    </li>
                    <li><a href="/article/1943962514060537856.htm"
                           title="Spring Cloud Gateway 的执行链路详解" target="_blank">Spring Cloud Gateway 的执行链路详解</a>
                        <span class="text-muted">愤怒的代码</span>
<a class="tag" taget="_blank" href="/search/SpringCloud/1.htm">SpringCloud</a><a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a><a class="tag" taget="_blank" href="/search/cloud/1.htm">cloud</a>
                        <div>SpringCloudGateway的执行链路详解核心目标明确SpringCloudGateway的请求处理全过程(从接收到请求→到转发→到返回响应),方便你在合适的生命周期节点插入你的逻辑。核心执行链路图(执行顺序)┌──────────────┐│客户端请求│└────┬─────────┘↓┌────┴─────────────┐│NettyHttpServer│←→ReactorNetty</div>
                    </li>
                    <li><a href="/article/1943962515373355008.htm"
                           title="Docker指定网桥和指定网桥IP" target="_blank">Docker指定网桥和指定网桥IP</a>
                        <span class="text-muted"></span>

                        <div>$dockernetworklsNETWORKIDNAMEDRIVER7fca4eb8c647bridgebridge9f904ee27bf5nonenullcf03ee007fb4hosthostBridge默认bridge网络,我们可以使用dockernetworkinspect命令查看返回的网络信息,我们使用dockerrun命令是将网络自动应用到新的容器Host如果是hosts模式,启动容</div>
                    </li>
                    <li><a href="/article/1943962387782627328.htm"
                           title="Java 调用 HTTP 接口的 7 种方式:全网最全指南" target="_blank">Java 调用 HTTP 接口的 7 种方式:全网最全指南</a>
                        <span class="text-muted"></span>

                        <div>Java调用HTTP接口的7种方式:全网最全指南在开发过程中,调用HTTP接口是最常见的需求之一。本文将详细介绍Java中7种主流的调用HTTP接口的方式,包括每种工具的优缺点和完整代码实现。1.使用RestTemplateRestTemplate是Spring提供的同步HTTP客户端,适用于传统项目。尽管从Spring5开始被标记为过时,它仍然是许多开发者的首选。示例代码importorg.sp</div>
                    </li>
                    <li><a href="/article/1943962261408247808.htm"
                           title="rocketmq的重试队列和死信队列" target="_blank">rocketmq的重试队列和死信队列</a>
                        <span class="text-muted">还不够</span>
<a class="tag" taget="_blank" href="/search/MQ/1.htm">MQ</a>
                        <div>原文:https://www.jianshu.com/p/1281f7fee69c消费端,一直不回传消费的结果。rocketmq认为消息没收到,consumer下一次拉取,broker依然会发送该消息。所以,任何异常都要捕获返回ConsumeConcurrentlyStatus.RECONSUME_LATERrocketmq会放到重试队列。这个重试TOPIC的名字是%RETRY%+consumer</div>
                    </li>
                    <li><a href="/article/1943962135029673984.htm"
                           title="UNIX域套接字" target="_blank">UNIX域套接字</a>
                        <span class="text-muted"></span>

                        <div>1、UNIX域套接字的定义UNIX域套接字是进程间通信(IPC)的一种方式,不涉及网络协议栈,因此在同一台主机上的通信中,它比基于TCP/IP协议的网络套接字更快速、更高效。2、UNIX域套接字的分类字节流套接字(SOCK_STREAM):提供面向连接的、可靠的数据传输服务。数据报套接字(SOCK_DGRAM):提供无连接的数据传输服务,数据以独立的数据报形式传输。3、UNIX套接字与TCP/IP</div>
                    </li>
                    <li><a href="/article/1943961251788943360.htm"
                           title="Kimi Chat 1.5 与 2.0 架构升级对比" target="_blank">Kimi Chat 1.5 与 2.0 架构升级对比</a>
                        <span class="text-muted">charles666666</span>
<a class="tag" taget="_blank" href="/search/%E4%BA%BA%E5%B7%A5%E6%99%BA%E8%83%BD/1.htm">人工智能</a><a class="tag" taget="_blank" href="/search/transformer/1.htm">transformer</a><a class="tag" taget="_blank" href="/search/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0/1.htm">深度学习</a><a class="tag" taget="_blank" href="/search/%E4%BA%A7%E5%93%81%E7%BB%8F%E7%90%86/1.htm">产品经理</a><a class="tag" taget="_blank" href="/search/chatgpt/1.htm">chatgpt</a>
                        <div>1.5版的MoE架构优化KimiChat1.5采用了优化后的MoE架构,其核心在于“专家网络动态路由”。这一机制类似于快递系统智能选择最优路径,能够根据输入数据的特性动态分配计算资源。这种优化显著提升了模型的计算效率,同时降低了硬件资源的浪费。在实际应用中,这意味着开发者可以在相同的硬件配置下处理更复杂的任务,或者在有限的资源下实现更高的性能。2.0的混合专家系统创新点与1.5版相比,KimiCh</div>
                    </li>
                    <li><a href="/article/1943961125532004352.htm"
                           title="数字孪生技术为UI前端注入新活力:实现产品设计的沉浸式体验" target="_blank">数字孪生技术为UI前端注入新活力:实现产品设计的沉浸式体验</a>
                        <span class="text-muted">ui设计前端开发老司机</span>
<a class="tag" taget="_blank" href="/search/ui/1.htm">ui</a>
                        <div>hello宝子们...我们是艾斯视觉擅长ui设计、前端开发、数字孪生、大数据、三维建模、三维动画10年+经验!希望我的分享能帮助到您!如需帮助可以评论关注私信我们一起探讨!致敬感谢感恩!一、引言:从“平面交互”到“沉浸体验”的UI革命当用户在电商APP中翻看3D家具模型却无法感知其与自家客厅的匹配度,当设计师在2D屏幕上绘制汽车内饰却难以预判实际乘坐体验——传统UI设计的“平面化、静态化、割裂感”</div>
                    </li>
                    <li><a href="/article/1943960369345130496.htm"
                           title="Java三年经验程序员技术栈全景指南:从前端到架构,对标阿里美团全栈要求" target="_blank">Java三年经验程序员技术栈全景指南:从前端到架构,对标阿里美团全栈要求</a>
                        <span class="text-muted">可曾去过倒悬山</span>
<a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E5%89%8D%E7%AB%AF/1.htm">前端</a><a class="tag" taget="_blank" href="/search/%E6%9E%B6%E6%9E%84/1.htm">架构</a>
                        <div>Java三年经验程序员技术栈全景指南:从前端到架构,对标阿里美团全栈要求三年经验是Java程序员的分水岭,技术栈深度决定你成为“业务码农”还是“架构师候选人”。本文整合阿里、美团、滴滴等大厂招聘要求,为你绘制可落地的进阶路线。一、Java核心:从语法糖到JVM底层三年经验与初级的核心差异在于系统级理解,大厂面试常考以下能力:JVM与性能调优内存模型(堆外内存、元空间)、GC算法(G1/ZGC适用场</div>
                    </li>
                    <li><a href="/article/1943960369915555840.htm"
                           title="无面试无offer? 你需要AI 求职co-pilot的帮助!" target="_blank">无面试无offer? 你需要AI 求职co-pilot的帮助!</a>
                        <span class="text-muted"></span>

                        <div>大家好啊,我写的开源免费求职AIco-pilot工具发布了v3.0.0,欢迎大家参与、使用!https://github.com/weicanie/prisma-ai一、项目介绍开源免费的求职co-pilot,自动化简历准备至offer到手的整个流程。优化您的项目、定制您的简历、为您匹配工作,并帮助您做好面试准备。二、核心价值prisma-ai旨在解决求职者在准备简历和寻找工作时最头疼的3个问题:</div>
                    </li>
                                <li><a href="/article/114.htm"
                                       title="戴尔笔记本win8系统改装win7系统" target="_blank">戴尔笔记本win8系统改装win7系统</a>
                                    <span class="text-muted">sophia天雪</span>
<a class="tag" taget="_blank" href="/search/win7/1.htm">win7</a><a class="tag" taget="_blank" href="/search/%E6%88%B4%E5%B0%94/1.htm">戴尔</a><a class="tag" taget="_blank" href="/search/%E6%94%B9%E8%A3%85%E7%B3%BB%E7%BB%9F/1.htm">改装系统</a><a class="tag" taget="_blank" href="/search/win8/1.htm">win8</a>
                                    <div>戴尔win8 系统改装win7 系统详述  
 
第一步:使用U盘制作虚拟光驱: 
        1)下载安装UltraISO:注册码可以在网上搜索。 
        2)启动UltraISO,点击“文件”—》“打开”按钮,打开已经准备好的ISO镜像文 
</div>
                                </li>
                                <li><a href="/article/241.htm"
                                       title="BeanUtils.copyProperties使用笔记" target="_blank">BeanUtils.copyProperties使用笔记</a>
                                    <span class="text-muted">bylijinnan</span>
<a class="tag" taget="_blank" href="/search/java/1.htm">java</a>
                                    <div>BeanUtils.copyProperties VS PropertyUtils.copyProperties 
 
两者最大的区别是: 
BeanUtils.copyProperties会进行类型转换,而PropertyUtils.copyProperties不会。 
既然进行了类型转换,那BeanUtils.copyProperties的速度比不上PropertyUtils.copyProp</div>
                                </li>
                                <li><a href="/article/368.htm"
                                       title="MyEclipse中文乱码问题" target="_blank">MyEclipse中文乱码问题</a>
                                    <span class="text-muted">0624chenhong</span>
<a class="tag" taget="_blank" href="/search/MyEclipse/1.htm">MyEclipse</a>
                                    <div>一、设置新建常见文件的默认编码格式,也就是文件保存的格式。 
在不对MyEclipse进行设置的时候,默认保存文件的编码,一般跟简体中文操作系统(如windows2000,windowsXP)的编码一致,即GBK。 
在简体中文系统下,ANSI 编码代表 GBK编码;在日文操作系统下,ANSI 编码代表 JIS 编码。 
Window-->Preferences-->General -</div>
                                </li>
                                <li><a href="/article/495.htm"
                                       title="发送邮件" target="_blank">发送邮件</a>
                                    <span class="text-muted">不懂事的小屁孩</span>
<a class="tag" taget="_blank" href="/search/send+email/1.htm">send email</a>
                                    <div>  
import org.apache.commons.mail.EmailAttachment;  
import org.apache.commons.mail.EmailException;  
import org.apache.commons.mail.HtmlEmail;  
import org.apache.commons.mail.MultiPartEmail;  
</div>
                                </li>
                                <li><a href="/article/622.htm"
                                       title="动画合集" target="_blank">动画合集</a>
                                    <span class="text-muted">换个号韩国红果果</span>
<a class="tag" taget="_blank" href="/search/html/1.htm">html</a><a class="tag" taget="_blank" href="/search/css/1.htm">css</a>
                                    <div>动画 指一种样式变为另一种样式 keyframes应当始终定义0 100 过程 
1 transition  制作鼠标滑过图片时的放大效果 
 

css
.wrap{
		width: 340px;height: 340px;
		position: absolute;
		top: 30%;
		left: 20%;
		overflow: hidden;
		bor</div>
                                </li>
                                <li><a href="/article/749.htm"
                                       title="网络最常见的攻击方式竟然是SQL注入" target="_blank">网络最常见的攻击方式竟然是SQL注入</a>
                                    <span class="text-muted">蓝儿唯美</span>
<a class="tag" taget="_blank" href="/search/sql%E6%B3%A8%E5%85%A5/1.htm">sql注入</a>
                                    <div>NTT研究表明,尽管SQL注入(SQLi)型攻击记录详尽且为人熟知,但目前网络应用程序仍然是SQLi攻击的重灾区。 
信息安全和风险管理公司NTTCom Security发布的《2015全球智能威胁风险报告》表明,目前黑客攻击网络应用程序方式中最流行的,要数SQLi攻击。报告对去年发生的60亿攻击 行为进行分析,指出SQLi攻击是最常见的网络应用程序攻击方式。全球网络应用程序攻击中,SQLi攻击占</div>
                                </li>
                                <li><a href="/article/876.htm"
                                       title="java笔记2" target="_blank">java笔记2</a>
                                    <span class="text-muted">a-john</span>
<a class="tag" taget="_blank" href="/search/java/1.htm">java</a>
                                    <div>类的封装: 
1,java中,对象就是一个封装体。封装是把对象的属性和服务结合成一个独立的的单位。并尽可能隐藏对象的内部细节(尤其是私有数据) 
2,目的:使对象以外的部分不能随意存取对象的内部数据(如属性),从而使软件错误能够局部化,减少差错和排错的难度。 
3,简单来说,“隐藏属性、方法或实现细节的过程”称为——封装。 
4,封装的特性: 
      4.1设置</div>
                                </li>
                                <li><a href="/article/1003.htm"
                                       title="[Andengine]Error:can't creat bitmap form path “gfx/xxx.xxx”" target="_blank">[Andengine]Error:can't creat bitmap form path “gfx/xxx.xxx”</a>
                                    <span class="text-muted">aijuans</span>
<a class="tag" taget="_blank" href="/search/%E5%AD%A6%E4%B9%A0Android%E9%81%87%E5%88%B0%E7%9A%84%E9%94%99%E8%AF%AF/1.htm">学习Android遇到的错误</a>
                                    <div>        最开始遇到这个错误是很早以前了,以前也没注意,只当是一个不理解的bug,因为所有的texture,textureregion都没有问题,但是就是提示错误。 
 
昨天和美工要图片,本来是要背景透明的png格式,可是她却给了我一个jpg的。说明了之后她说没法改,因为没有png这个保存选项。 
 
我就看了一下,和她要了psd的文件,还好我有一点</div>
                                </li>
                                <li><a href="/article/1130.htm"
                                       title="自己写的一个繁体到简体的转换程序" target="_blank">自己写的一个繁体到简体的转换程序</a>
                                    <span class="text-muted">asialee</span>
<a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/%E8%BD%AC%E6%8D%A2/1.htm">转换</a><a class="tag" taget="_blank" href="/search/%E7%B9%81%E4%BD%93/1.htm">繁体</a><a class="tag" taget="_blank" href="/search/filter/1.htm">filter</a><a class="tag" taget="_blank" href="/search/%E7%AE%80%E4%BD%93/1.htm">简体</a>
                                    <div>          今天调研一个任务,基于java的filter实现繁体到简体的转换,于是写了一个demo,给各位博友奉上,欢迎批评指正。 
         实现的思路是重载request的调取参数的几个方法,然后做下转换。 
          </div>
                                </li>
                                <li><a href="/article/1257.htm"
                                       title="android意图和意图监听器技术" target="_blank">android意图和意图监听器技术</a>
                                    <span class="text-muted">百合不是茶</span>
<a class="tag" taget="_blank" href="/search/android/1.htm">android</a><a class="tag" taget="_blank" href="/search/%E6%98%BE%E7%A4%BA%E6%84%8F%E5%9B%BE/1.htm">显示意图</a><a class="tag" taget="_blank" href="/search/%E9%9A%90%E5%BC%8F%E6%84%8F%E5%9B%BE/1.htm">隐式意图</a><a class="tag" taget="_blank" href="/search/%E6%84%8F%E5%9B%BE%E7%9B%91%E5%90%AC%E5%99%A8/1.htm">意图监听器</a>
                                    <div>Intent是在activity之间传递数据;Intent的传递分为显示传递和隐式传递 
  
显式意图:调用Intent.setComponent() 或 Intent.setClassName() 或 Intent.setClass()方法明确指定了组件名的Intent为显式意图,显式意图明确指定了Intent应该传递给哪个组件。 
  
隐式意图;不指明调用的名称,根据设</div>
                                </li>
                                <li><a href="/article/1384.htm"
                                       title="spring3中新增的@value注解" target="_blank">spring3中新增的@value注解</a>
                                    <span class="text-muted">bijian1013</span>
<a class="tag" taget="_blank" href="/search/java/1.htm">java</a><a class="tag" taget="_blank" href="/search/spring/1.htm">spring</a><a class="tag" taget="_blank" href="/search/%40Value/1.htm">@Value</a>
                                    <div>        在spring 3.0中,可以通过使用@value,对一些如xxx.properties文件中的文件,进行键值对的注入,例子如下: 
1.首先在applicationContext.xml中加入:    
<beans xmlns="http://www.springframework.</div>
                                </li>
                                <li><a href="/article/1511.htm"
                                       title="Jboss启用CXF日志" target="_blank">Jboss启用CXF日志</a>
                                    <span class="text-muted">sunjing</span>
<a class="tag" taget="_blank" href="/search/log/1.htm">log</a><a class="tag" taget="_blank" href="/search/jboss/1.htm">jboss</a><a class="tag" taget="_blank" href="/search/CXF/1.htm">CXF</a>
                                    <div>1. 在standalone.xml配置文件中添加system-properties: 
    <system-properties>        <property name="org.apache.cxf.logging.enabled" value=&</div>
                                </li>
                                <li><a href="/article/1638.htm"
                                       title="【Hadoop三】Centos7_x86_64部署Hadoop集群之编译Hadoop源代码" target="_blank">【Hadoop三】Centos7_x86_64部署Hadoop集群之编译Hadoop源代码</a>
                                    <span class="text-muted">bit1129</span>
<a class="tag" taget="_blank" href="/search/centos/1.htm">centos</a>
                                    <div>  编译必需的软件 
 
 Firebugs3.0.0 
 Maven3.2.3 
 Ant 
 JDK1.7.0_67 
 protobuf-2.5.0 
 Hadoop 2.5.2源码包 
 
  
  
  
 
 Firebugs3.0.0 
 
  
http://sourceforge.jp/projects/sfnet_findbug</div>
                                </li>
                                <li><a href="/article/1765.htm"
                                       title="struts2验证框架的使用和扩展" target="_blank">struts2验证框架的使用和扩展</a>
                                    <span class="text-muted">白糖_</span>
<a class="tag" taget="_blank" href="/search/%E6%A1%86%E6%9E%B6/1.htm">框架</a><a class="tag" taget="_blank" href="/search/xml/1.htm">xml</a><a class="tag" taget="_blank" href="/search/bean/1.htm">bean</a><a class="tag" taget="_blank" href="/search/struts/1.htm">struts</a><a class="tag" taget="_blank" href="/search/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F/1.htm">正则表达式</a>
                                    <div>struts2能够对前台提交的表单数据进行输入有效性校验,通常有两种方式: 
1、在Action类中通过validatexx方法验证,这种方式很简单,在此不再赘述; 
2、通过编写xx-validation.xml文件执行表单验证,当用户提交表单请求后,struts会优先执行xml文件,如果校验不通过是不会让请求访问指定action的。 
本文介绍一下struts2通过xml文件进行校验的方法并说</div>
                                </li>
                                <li><a href="/article/1892.htm"
                                       title="记录-感悟" target="_blank">记录-感悟</a>
                                    <span class="text-muted">braveCS</span>
<a class="tag" taget="_blank" href="/search/%E6%84%9F%E6%82%9F/1.htm">感悟</a>
                                    <div>再翻翻以前写的感悟,有时会发现自己很幼稚,也会让自己找回初心。 
  
2015-1-11  1. 能在工作之余学习感兴趣的东西已经很幸福了; 
2. 要改变自己,不能这样一直在原来区域,要突破安全区舒适区,才能提高自己,往好的方面发展; 
3. 多反省多思考;要会用工具,而不是变成工具的奴隶; 
4. 一天内集中一个定长时间段看最新资讯和偏流式博</div>
                                </li>
                                <li><a href="/article/2019.htm"
                                       title="编程之美-数组中最长递增子序列" target="_blank">编程之美-数组中最长递增子序列</a>
                                    <span class="text-muted">bylijinnan</span>
<a class="tag" taget="_blank" href="/search/%E7%BC%96%E7%A8%8B%E4%B9%8B%E7%BE%8E/1.htm">编程之美</a>
                                    <div>
import java.util.Arrays;
import java.util.Random;

public class LongestAccendingSubSequence {

	/**
	 * 编程之美 数组中最长递增子序列 
	 * 书上的解法容易理解
	 * 另一方法书上没有提到的是,可以将数组排序(由小到大)得到新的数组,
	 * 然后求排序后的数组与原数</div>
                                </li>
                                <li><a href="/article/2146.htm"
                                       title="读书笔记5" target="_blank">读书笔记5</a>
                                    <span class="text-muted">chengxuyuancsdn</span>
<a class="tag" taget="_blank" href="/search/%E9%87%8D%E5%A4%8D%E6%8F%90%E4%BA%A4/1.htm">重复提交</a><a class="tag" taget="_blank" href="/search/struts2%E7%9A%84token%E9%AA%8C%E8%AF%81/1.htm">struts2的token验证</a>
                                    <div>1、重复提交 
2、struts2的token验证 
3、用response返回xml时的注意 
 
1、重复提交 
(1)应用场景 
(1-1)点击提交按钮两次。 
(1-2)使用浏览器后退按钮重复之前的操作,导致重复提交表单。 
(1-3)刷新页面 
(1-4)使用浏览器历史记录重复提交表单。 
(1-5)浏览器重复的 HTTP 请求。 
(2)解决方法 
(2-1)禁掉提交按钮 
(2-2)</div>
                                </li>
                                <li><a href="/article/2273.htm"
                                       title="[时空与探索]全球联合进行第二次费城实验的可能性" target="_blank">[时空与探索]全球联合进行第二次费城实验的可能性</a>
                                    <span class="text-muted">comsci</span>

                                    <div> 
 
     二次世界大战前后,由爱因斯坦参加的一次在海军舰艇上进行的物理学实验 -费城实验 
  至今给我们大家留下很多迷团..... 
 
     关于费城实验的详细过程,大家可以在网络上搜索一下,我这里就不详细描述了 
 
     在这里,我的意思是,现在</div>
                                </li>
                                <li><a href="/article/2400.htm"
                                       title="easy connect 之 ORA-12154: TNS: 无法解析指定的连接标识符" target="_blank">easy connect 之 ORA-12154: TNS: 无法解析指定的连接标识符</a>
                                    <span class="text-muted">daizj</span>
<a class="tag" taget="_blank" href="/search/oracle/1.htm">oracle</a><a class="tag" taget="_blank" href="/search/ORA-12154/1.htm">ORA-12154</a>
                                    <div>用easy connect连接出现“tns无法解析指定的连接标示符”的错误,如下: 
C:\Users\Administrator>sqlplus username/pwd@192.168.0.5:1521/orcl 
SQL*Plus: Release 10.2.0.1.0 – Production on 星期一 5月 21 18:16:20 2012 
Copyright (c) 198</div>
                                </li>
                                <li><a href="/article/2527.htm"
                                       title="简单排序:归并排序" target="_blank">简单排序:归并排序</a>
                                    <span class="text-muted">dieslrae</span>
<a class="tag" taget="_blank" href="/search/%E5%BD%92%E5%B9%B6%E6%8E%92%E5%BA%8F/1.htm">归并排序</a>
                                    <div>
    public void mergeSort(int[] array){
        int temp = array.length/2;
        
        if(temp == 0){
            return;
        }
        
        int[] a = new int[temp];
        int</div>
                                </li>
                                <li><a href="/article/2654.htm"
                                       title="C语言中字符串的\0和空格" target="_blank">C语言中字符串的\0和空格</a>
                                    <span class="text-muted">dcj3sjt126com</span>
<a class="tag" taget="_blank" href="/search/c/1.htm">c</a>
                                    <div>   \0 为字符串结束符,比如说: 
                      abcd (空格)cdefg; 
存入数组时,空格作为一个字符占有一个字节的空间,我们</div>
                                </li>
                                <li><a href="/article/2781.htm"
                                       title="解决Composer国内速度慢的办法" target="_blank">解决Composer国内速度慢的办法</a>
                                    <span class="text-muted">dcj3sjt126com</span>
<a class="tag" taget="_blank" href="/search/Composer/1.htm">Composer</a>
                                    <div>用法: 
有两种方式启用本镜像服务: 
1 将以下配置信息添加到 Composer 的配置文件 config.json 中(系统全局配置)。见“例1” 
2 将以下配置信息添加到你的项目的 composer.json 文件中(针对单个项目配置)。见“例2” 
为了避免安装包的时候都要执行两次查询,切记要添加禁用 packagist 的设置,如下      1   2   3   4   5    </div>
                                </li>
                                <li><a href="/article/2908.htm"
                                       title="高效可伸缩的结果缓存" target="_blank">高效可伸缩的结果缓存</a>
                                    <span class="text-muted">shuizhaosi888</span>
<a class="tag" taget="_blank" href="/search/%E9%AB%98%E6%95%88%E5%8F%AF%E4%BC%B8%E7%BC%A9%E7%9A%84%E7%BB%93%E6%9E%9C%E7%BC%93%E5%AD%98/1.htm">高效可伸缩的结果缓存</a>
                                    <div>/**
 * 要执行的算法,返回结果v
 */
public interface Computable<A, V> {
	public V comput(final A arg);

}
 
  
/**
 * 用于缓存数据
 */
public class Memoizer<A, V> implements Computable<A, </div>
                                </li>
                                <li><a href="/article/3035.htm"
                                       title="三点定位的算法" target="_blank">三点定位的算法</a>
                                    <span class="text-muted">haoningabc</span>
<a class="tag" taget="_blank" href="/search/c/1.htm">c</a><a class="tag" taget="_blank" href="/search/%E7%AE%97%E6%B3%95/1.htm">算法</a>
                                    <div>三点定位, 
已知a,b,c三个顶点的x,y坐标 
和三个点都z坐标的距离,la,lb,lc 
 
求z点的坐标 
原理就是围绕a,b,c 三个点画圆,三个圆焦点的部分就是所求 
但是,由于三个点的距离可能不准,不一定会有结果, 
所以是三个圆环的焦点,环的宽度开始为0,没有取到则加1 
运行 
gcc -lm test.c 
test.c代码如下 
 

#include "stdi</div>
                                </li>
                                <li><a href="/article/3162.htm"
                                       title="epoll使用详解" target="_blank">epoll使用详解</a>
                                    <span class="text-muted">jimmee</span>
<a class="tag" taget="_blank" href="/search/c/1.htm">c</a><a class="tag" taget="_blank" href="/search/linux/1.htm">linux</a><a class="tag" taget="_blank" href="/search/%E6%9C%8D%E5%8A%A1%E7%AB%AF%E7%BC%96%E7%A8%8B/1.htm">服务端编程</a><a class="tag" taget="_blank" href="/search/epoll/1.htm">epoll</a>
                                    <div>epoll - I/O event notification facility在linux的网络编程中,很长的时间都在使用select来做事件触发。在linux新的内核中,有了一种替换它的机制,就是epoll。相比于select,epoll最大的好处在于它不会随着监听fd数目的增长而降低效率。因为在内核中的select实现中,它是采用轮询来处理的,轮询的fd数目越多,自然耗时越多。并且,在linu</div>
                                </li>
                                <li><a href="/article/3289.htm"
                                       title="Hibernate对Enum的映射的基本使用方法" target="_blank">Hibernate对Enum的映射的基本使用方法</a>
                                    <span class="text-muted">linzx0212</span>
<a class="tag" taget="_blank" href="/search/enum/1.htm">enum</a><a class="tag" taget="_blank" href="/search/Hibernate/1.htm">Hibernate</a>
                                    <div>  
枚举 
  
/**
 * 性别枚举
 */
public enum Gender {

    MALE(0), FEMALE(1), OTHER(2);

    private Gender(int i) {
        this.i = i;
    }

    private int i;

    public int getI</div>
                                </li>
                                <li><a href="/article/3416.htm"
                                       title="第10章 高级事件(下)" target="_blank">第10章 高级事件(下)</a>
                                    <span class="text-muted">onestopweb</span>
<a class="tag" taget="_blank" href="/search/%E4%BA%8B%E4%BB%B6/1.htm">事件</a>
                                    <div>index.html 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/</div>
                                </li>
                                <li><a href="/article/3543.htm"
                                       title="孙子兵法" target="_blank">孙子兵法</a>
                                    <span class="text-muted">roadrunners</span>
<a class="tag" taget="_blank" href="/search/%E5%AD%99%E5%AD%90/1.htm">孙子</a><a class="tag" taget="_blank" href="/search/%E5%85%B5%E6%B3%95/1.htm">兵法</a>
                                    <div>始计第一 
 
孙子曰: 
兵者,国之大事,死生之地,存亡之道,不可不察也。 
故经之以五事,校之以计,而索其情:一曰道,二曰天,三曰地,四曰将,五 
曰法。道者,令民于上同意,可与之死,可与之生,而不危也;天者,阴阳、寒暑 
、时制也;地者,远近、险易、广狭、死生也;将者,智、信、仁、勇、严也;法 
者,曲制、官道、主用也。凡此五者,将莫不闻,知之者胜,不知之者不胜。故校 
之以计,而索其情,曰</div>
                                </li>
                                <li><a href="/article/3670.htm"
                                       title="MySQL双向复制" target="_blank">MySQL双向复制</a>
                                    <span class="text-muted">tomcat_oracle</span>
<a class="tag" taget="_blank" href="/search/mysql/1.htm">mysql</a>
                                    <div>本文包括: 
 
  主机配置  
  从机配置  
  建立主-从复制  
  建立双向复制  
 
  背景 
按照以下简单的步骤: 
参考一下: 
 
  在机器A配置主机(192.168.1.30)  
  在机器B配置从机(192.168.1.29)  
  我们可以使用下面的步骤来实现这一点  
 
  
步骤1:机器A设置主机 
 
  在主机中打开配置文件 , </div>
                                </li>
                                <li><a href="/article/3797.htm"
                                       title="zoj 3822 Domination(dp)" target="_blank">zoj 3822 Domination(dp)</a>
                                    <span class="text-muted">阿尔萨斯</span>
<a class="tag" taget="_blank" href="/search/Mina/1.htm">Mina</a>
                                    <div> 题目链接:zoj 3822 Domination 
 题目大意:给定一个N∗M的棋盘,每次任选一个位置放置一枚棋子,直到每行每列上都至少有一枚棋子,问放置棋子个数的期望。 
 解题思路:大白书上概率那一张有一道类似的题目,但是因为时间比较久了,还是稍微想了一下。dp[i][j][k]表示i行j列上均有至少一枚棋子,并且消耗k步的概率(k≤i∗j),因为放置在i+1~n上等价与放在i+1行上,同理</div>
                                </li>
                </ul>
            </div>
        </div>
    </div>

<div>
    <div class="container">
        <div class="indexes">
            <strong>按字母分类:</strong>
            <a href="/tags/A/1.htm" target="_blank">A</a><a href="/tags/B/1.htm" target="_blank">B</a><a href="/tags/C/1.htm" target="_blank">C</a><a
                href="/tags/D/1.htm" target="_blank">D</a><a href="/tags/E/1.htm" target="_blank">E</a><a href="/tags/F/1.htm" target="_blank">F</a><a
                href="/tags/G/1.htm" target="_blank">G</a><a href="/tags/H/1.htm" target="_blank">H</a><a href="/tags/I/1.htm" target="_blank">I</a><a
                href="/tags/J/1.htm" target="_blank">J</a><a href="/tags/K/1.htm" target="_blank">K</a><a href="/tags/L/1.htm" target="_blank">L</a><a
                href="/tags/M/1.htm" target="_blank">M</a><a href="/tags/N/1.htm" target="_blank">N</a><a href="/tags/O/1.htm" target="_blank">O</a><a
                href="/tags/P/1.htm" target="_blank">P</a><a href="/tags/Q/1.htm" target="_blank">Q</a><a href="/tags/R/1.htm" target="_blank">R</a><a
                href="/tags/S/1.htm" target="_blank">S</a><a href="/tags/T/1.htm" target="_blank">T</a><a href="/tags/U/1.htm" target="_blank">U</a><a
                href="/tags/V/1.htm" target="_blank">V</a><a href="/tags/W/1.htm" target="_blank">W</a><a href="/tags/X/1.htm" target="_blank">X</a><a
                href="/tags/Y/1.htm" target="_blank">Y</a><a href="/tags/Z/1.htm" target="_blank">Z</a><a href="/tags/0/1.htm" target="_blank">其他</a>
        </div>
    </div>
</div>
<footer id="footer" class="mb30 mt30">
    <div class="container">
        <div class="footBglm">
            <a target="_blank" href="/">首页</a> -
            <a target="_blank" href="/custom/about.htm">关于我们</a> -
            <a target="_blank" href="/search/Java/1.htm">站内搜索</a> -
            <a target="_blank" href="/sitemap.txt">Sitemap</a> -
            <a target="_blank" href="/custom/delete.htm">侵权投诉</a>
        </div>
        <div class="copyright">版权所有 IT知识库 CopyRight © 2000-2050 E-COM-NET.COM , All Rights Reserved.
<!--            <a href="https://beian.miit.gov.cn/" rel="nofollow" target="_blank">京ICP备09083238号</a><br>-->
        </div>
    </div>
</footer>
<!-- 代码高亮 -->
<script type="text/javascript" src="/static/syntaxhighlighter/scripts/shCore.js"></script>
<script type="text/javascript" src="/static/syntaxhighlighter/scripts/shLegacy.js"></script>
<script type="text/javascript" src="/static/syntaxhighlighter/scripts/shAutoloader.js"></script>
<link type="text/css" rel="stylesheet" href="/static/syntaxhighlighter/styles/shCoreDefault.css"/>
<script type="text/javascript" src="/static/syntaxhighlighter/src/my_start_1.js"></script>





</body>

</html>