{"id":306600,"date":"2020-07-07T21:00:34","date_gmt":"2020-07-07T21:00:34","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=306600"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=306600","title":{"rendered":"\u041a\u0430\u043a \u0441\u043a\u0430\u0447\u0430\u0442\u044c \u0444\u0430\u0439\u043b \u043f\u043e\u0440\u0446\u0438\u044f\u043c\u0438?"},"content":{"rendered":"\n<div class=\"post__text post__text-html post__text_v1\" id=\"post-content-body\" data-io-article-url=\"https:\/\/habr.com\/ru\/post\/503984\/\">\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/nk\/rg\/wy\/nkrgwyimwne_fs4v1fmhxwzbjr4.png\"><\/div>\n<p>  \u0418\u043d\u043e\u0433\u0434\u0430 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u0442\u044c \u0444\u0430\u0439\u043b \u043f\u043e\u0440\u0446\u0438\u044f\u043c\u0438. \u041f\u0440\u0438\u0447\u0438\u043d\u044b \u0431\u044b\u0432\u0430\u044e\u0442 \u0440\u0430\u0437\u043d\u044b\u0435, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u201c\u0431\u043e\u043b\u044c\u0448\u043e\u0439\u201d \u043e\u0431\u044a\u0435\u043c \u0444\u0430\u0439\u043b\u0430, \u0448\u0438\u0440\u0438\u043d\u0430 \u043a\u0430\u043d\u0430\u043b\u0430 \u043d\u0435 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u0430 \u0438\u043b\u0438 \u0441\u0435\u0440\u0432\u0435\u0440 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0438\u0432\u0430\u0435\u0442 \u043e\u0431\u044a\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u044f.<\/p>\n<p>  \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043e\u043f\u0438\u0448\u0443 \u043a\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u0430 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u043c\u0438 \u043f\u043e\u0440\u0446\u0438\u044f\u043c\u0438 \u043d\u0430 \u044f\u0437\u044b\u043a\u0435 Java \u043f\u043e \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0443 HTTP.<\/p>\n<h2>\u041e\u0431 HTTP<\/h2>\n<p>  \u0414\u043b\u044f \u0442\u0430\u043a\u0438\u0445 \u0446\u0435\u043b\u0435\u0439 HTTP \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a <b><code>Range<\/code><\/b> \u0434\u043b\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u0430. \u0412 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0434\u0438\u0430\u043f\u0430\u0437\u043e\u043d \u0431\u0430\u0439\u0442\u043e\u0432 \u0434\u043b\u044f \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u044f. \u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a <code>Range<\/code> \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043a \u0442\u0435\u043b\u0443 \u0437\u0430\u043f\u0440\u043e\u0441\u0430, \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u0441\u044e\u0434\u0430 \u043d\u0435 \u0432\u0445\u043e\u0434\u044f\u0442.<\/p>\n<p>  \u0421\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0444\u043e\u0440\u043c\u0430\u0442\u044b \u0443\u043a\u0430\u0437\u0430\u043d\u0438\u044f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430:<\/p>\n<pre><code class=\"markdown\">Range: bytes=first-byte-pos &quot;-&quot; [last-byte-pos]<\/code><\/pre>\n<p>  <b>first-byte-pos<\/b> \u2014 \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043c\u0435\u0449\u0435\u043d\u0438\u0435 \u0431\u0430\u0439\u0442\u0430 \u0441 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043d\u0430\u0447\u0430\u0442\u044c (\u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u044c) \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u0435, \u043e\u043d\u043e \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u0435 \u043b\u0438\u0431\u043e \u0440\u0430\u0432\u043d\u043e 0, \u0438 \u043c\u0435\u043d\u044c\u0448\u0435 \u043b\u0438\u0431\u043e \u0440\u0430\u0432\u043d\u043e last-byte-pos;<\/p>\n<p>  <b>last-byte-pos<\/b> \u2014 \u043a\u043e\u043d\u0435\u0447\u043d\u043e\u0435 \u0441\u043c\u0435\u0449\u0435\u043d\u0438\u0435 \u0431\u0430\u0439\u0442\u0430 \u0434\u043e \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u043a\u0430\u0447\u0430\u0442\u044c \u0444\u0430\u0439\u043b, \u043e\u043d\u043e \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u0435 \u043b\u0438\u0431\u043e \u0440\u0430\u0432\u043d\u043e first-byte-pos \u0438 \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u043c\u0435\u043d\u044c\u0448\u0435 \u043b\u0438\u0431\u043e \u0440\u0430\u0432\u043d\u043e \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u0435\u043c\u043e\u043c\u0443 \u0440\u0430\u0437\u043c\u0435\u0440\u0443 \u0444\u0430\u0439\u043b\u0430 \u043c\u0438\u043d\u0443\u0441 \u043e\u0434\u0438\u043d (\u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u044d\u0442\u043e \u0441\u043c\u0435\u0449\u0435\u043d\u0438\u0435, \u0442\u043e \u0435\u0441\u0442\u044c \u0438\u043d\u0434\u0435\u043a\u0441 \u0432 \u043c\u0430\u0441\u0441\u0438\u0432\u0435 \u0431\u0430\u0439\u0442\u043e\u0432).<br \/>  <a name=\"habracut\"><\/a>  <\/p>\n<h4>\u041f\u0440\u0438\u043c\u0435\u0440\u044b<\/h4>\n<p>  <b>\u0418\u0441\u043a\u043b\u044e\u0447\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u043e \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u043c\u0443 \u0434\u0438\u0430\u043f\u0430\u0437\u043e\u043d\u0443<\/b><\/p>\n<pre><code class=\"markdown\">bytes=0-255<\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"markdown\">bytes=256-512<\/code><\/pre>\n<p>  <b>\u0421\u043a\u0430\u0447\u0430\u0442\u044c \u043d\u0430\u0447\u0438\u043d\u0430\u044f \u0441 \u043f\u043e\u0437\u0438\u0446\u0438\u0438 first-byte-pos \u0434\u043e \u043a\u043e\u043d\u0446\u0430<\/b><\/p>\n<pre><code class=\"markdown\">Range: bytes=first-byte-pos &quot;-&quot;<\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"markdown\">bytes=512-<\/code><\/pre>\n<p>  <b>\u0421\u043a\u0430\u0447\u0430\u0442\u044c last-byte-pos \u0441 \u043a\u043e\u043d\u0446\u0430<\/b><\/p>\n<pre><code class=\"markdown\">Range: bytes=&quot;-&quot;last-byte-pos<\/code><\/pre>\n<p>  <\/p>\n<pre><code class=\"markdown\">bytes=-32<\/code><\/pre>\n<p>  <\/p>\n<h4>\u041d\u0430 \u043f\u043e\u0434\u043e\u0431\u043d\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 \u0441\u0435\u0440\u0432\u0435\u0440 \u0432 \u043e\u0442\u0432\u0435\u0442 \u043f\u0440\u0438\u0448\u043b\u0451\u0442 \u0434\u0432\u0430 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0445 \u0441\u0442\u0430\u0442\u0443\u0441\u0430<\/h4>\n<p>  <\/p>\n<ul>\n<li><b><code>206 Partial Content<\/code><\/b> \u2014 \u0444\u0430\u0439\u043b \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0441\u043a\u0430\u0447\u0430\u043d \u0447\u0430\u0441\u0442\u0438\u0447\u043d\u043e;<\/li>\n<li><b><code>416 Range Not Satisfiable<\/code><\/b> \u2014 \u043d\u0435\u0443\u0434\u043e\u0432\u043b\u0435\u0442\u0432\u043e\u0440\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0434\u0438\u0430\u043f\u0430\u0437\u043e\u043d \u0434\u043b\u044f \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u044f.<\/li>\n<\/ul>\n<p>  \u041a\u043e\u043d\u0435\u0447\u043d\u043e \u0436\u0435 \u043e\u0442\u0432\u0435\u0442\u043e\u0432 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u0435. \u0412 \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0435 \u0441\u0442\u0430\u0442\u044c\u0438 \u043e\u043d\u0438 \u043d\u0430\u0441 \u043d\u0435 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u0443\u044e\u0442.<\/p>\n<p>  \u0418 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a <b><code>Content-Range<\/code><\/b> \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0443\u043a\u0430\u0437\u0430\u043d \u0437\u0430\u043f\u0440\u043e\u0448\u0435\u043d\u043d\u044b\u0439 \u0434\u0438\u0430\u043f\u0430\u0437\u043e\u043d \u0438 \u043e\u0431\u0449\u0438\u0439 \u0440\u0430\u0437\u043c\u0435\u0440.<\/p>\n<pre><code class=\"markdown\">Content-Range: bytes 256-512\/1024<\/code><\/pre>\n<p>  \u042d\u0442\u043e\u0442 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a \u0441\u043e\u043e\u0431\u0449\u0430\u0435\u0442 \u0447\u0442\u043e \u043f\u0440\u0438\u0448\u0451\u043b \u043e\u0442\u0432\u0435\u0442 \u043d\u0430 \u0437\u0430\u043f\u0440\u043e\u0441 \u0441 <b>256-512<\/b> \u043f\u043e\u0437\u0438\u0446\u0438\u0438 \u0432 \u043c\u0430\u0441\u0441\u0438\u0432\u0435 \u0431\u0430\u0439\u0442\u043e\u0432 \u0438\u0437 <b>1024<\/b> \u0431\u0430\u0439\u0442\u043e\u0432.<\/p>\n<h2>\u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u043d\u0430 Java 14<\/h2>\n<p>  \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 HTTP \u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0432\u043e\u0437\u044c\u043c\u0435\u043c \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u0438\u0437 JDK, \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0439 \u0441 Java 11 \u2014 <code>java.net.http.HttpClient<\/code>.<\/p>\n<p>  \u0414\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043b\u043e\u0433\u0438\u043a\u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043f\u043e \u043f\u043e\u0440\u0446\u0438\u044f\u043c, \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u043a\u043b\u0430\u0441\u0441 \u043e\u0431\u0451\u0440\u0442\u043a\u0443 \u2014 <code>art.aukhatov.http.WebClient<\/code>.<\/p>\n<p>  <b>\u041e\u043f\u0438\u0448\u0435\u043c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u044d\u0442\u043e\u0433\u043e \u043a\u043b\u0430\u0441\u0441\u0430<\/b><\/p>\n<ul>\n<li><b><code>byte[] download(String uri, int chunkSize)<\/code><\/b> \u2014 \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u0435\u0442 \u0444\u0430\u0439\u043b \u043f\u043e \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u043c \u043f\u043e\u0440\u0446\u0438\u044f\u043c \u0431\u0430\u0439\u0442\u043e\u0432;<\/li>\n<li><b><code>Response download(String uri, int firstBytePos, int lastBytePos)<\/code><\/b> \u2014 \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u0435\u0442 \u0444\u0430\u0439\u043b \u043f\u043e \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u043e\u043c\u0443 \u0434\u0438\u0430\u043f\u0430\u0437\u043e\u043d\u0443.<\/li>\n<\/ul>\n<p>  \u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u0435\u0441\u043b\u0438 \u043f\u0435\u0440\u0435\u0434\u0430\u043d\u043d\u044b\u0439 URI \u043d\u0435 \u0432\u0430\u043b\u0438\u0434\u043d\u044b\u0439, \u0442\u043e \u043c\u0435\u0442\u043e\u0434 \u0431\u0440\u043e\u0441\u0430\u0435\u0442 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 <code>java.net.URISyntaxException<\/code>. \u0418\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 <code>java.io.IOException<\/code> \u0431\u0440\u043e\u0441\u0430\u0435\u0442\u0441\u044f \u0435\u0441\u043b\u0438 \u043a\u0430\u043a\u0430\u044f-\u043b\u0438\u0431\u043e \u043d\u0435\u043e\u0436\u0438\u0434\u0430\u043d\u043d\u0430\u044f \u043e\u0448\u0438\u0431\u043a\u0430 \u0441 \u0432\u0432\u043e\u0434\u043e\u043c\/\u0432\u044b\u0432\u043e\u0434\u043e\u043c.<\/p>\n<h4>\u041a\u043b\u0430\u0441\u0441\u044b WebClient \u0438 Response<\/h4>\n<p>  <\/p>\n<pre><code class=\"java\">package art.aukhatov.http;  import java.io.BufferedInputStream; import java.net.http.HttpClient; import java.net.http.HttpHeaders; import java.time.Duration;  public class WebClient {       private final HttpClient httpClient;       public WebClient() {          this.httpClient = HttpClient.newBuilder()               .connectTimeout(Duration.ofSeconds(10))               .build();      }        public static class Response {           final BufferedInputStream inputStream;           final int status;           final HttpHeaders headers;            public Response(BufferedInputStream inputStream, int status, HttpHeaders headers) {                this.inputStream = inputStream;                this.status = status;                this.headers = headers;           }      } }<\/code><\/pre>\n<p>  \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043e\u0442\u0432\u0435\u0442\u0430 \u043e\u043f\u0438\u0448\u0435\u043c <code>nested class WebClient.Response<\/code> \u0441 \u043f\u043e\u043b\u044f\u043c\u0438 BufferedInputStream, HTTP Status, HTTP Header. \u042d\u0442\u0438 \u0434\u0430\u043d\u043d\u044b\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b \u0434\u043b\u044f \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0438\u0440\u0443\u044e\u0449\u0435\u0433\u043e \u043c\u0430\u0441\u0441\u0438\u0432\u0430 \u0431\u0430\u0439\u0442\u043e\u0432 \u0438 \u043f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u044f \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0442\u044c \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u0442\u044c \u0438\u043b\u0438 \u043d\u0435\u0442.<\/p>\n<h4>\u041c\u0435\u0442\u043e\u0434 Response download(final String uri, int firstBytePos, int lastBytePos)<\/h4>\n<p>  <\/p>\n<pre><code class=\"java\">import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; import java.net.http.HttpClient; import java.net.http.HttpHeaders; import java.net.http.HttpRequest; import java.net.http.HttpResponse;  private static final String HEADER_RANGE = &quot;Range&quot;; private static final String RANGE_FORMAT = &quot;bytes=%d-%d&quot;;  public Response download(final String uri, int firstBytePos, int lastBytePos)     throws URISyntaxException, IOException, InterruptedException {      HttpRequest request = HttpRequest             .newBuilder(new URI(uri))             .header(HEADER_RANGE, format(RANGE_FORMAT, firstBytePos, lastBytePos))             .GET()             .version(HttpClient.Version.HTTP_2)             .build();      HttpResponse&lt;InputStream&gt; response = httpClient.send(request, HttpResponse.BodyHandlers.ofInputStream());      return new Response(new BufferedInputStream(response.body()), response.statusCode(), response.headers()); } <\/code><\/pre>\n<p>  \u042d\u0442\u043e\u0442 \u043c\u0435\u0442\u043e\u0434 \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u0435\u0442 \u0443\u043a\u0430\u0437\u0430\u043d\u043d\u044b\u0439 \u0434\u0438\u0430\u043f\u0430\u0437\u043e\u043d \u0434\u0430\u043d\u043d\u044b\u0445. \u041d\u043e \u043f\u0440\u0435\u0436\u0434\u0435 \u0447\u0435\u043c \u043d\u0430\u0447\u0430\u0442\u044c \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0437\u043d\u0430\u0442\u044c \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0432\u0441\u0435\u0433\u043e \u0434\u0430\u043d\u043d\u044b\u0445 \u043d\u0430\u043c \u043d\u0430\u0434\u043e \u043e\u0436\u0438\u0434\u0430\u0442\u044c. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441 \u0431\u0435\u0437 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043a\u043e\u043d\u0442\u0435\u043d\u0442\u0430. \u0412\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f \u043c\u0435\u0442\u043e\u0434\u043e\u043c <code>HEAD<\/code>.<\/p>\n<h4>\u041c\u0435\u0442\u043e\u0434 long contentLength(final String uri)<\/h4>\n<p>  <\/p>\n<pre><code class=\"java\">import java.util.OptionalLong;  private static final String HTTP_HEAD = &quot;HEAD&quot;; private static final String HEADER_CONTENT_LENGTH = &quot;content-length&quot;;  private long contentLength(final String uri) \t\t\tthrows URISyntaxException, IOException, InterruptedException {      HttpRequest headRequest = HttpRequest             .newBuilder(new URI(uri))             .method(HTTP_HEAD, HttpRequest.BodyPublishers.noBody())             .version(HttpClient.Version.HTTP_2)             .build();      HttpResponse&lt;String&gt; httpResponse = httpClient.send(headRequest, HttpResponse.BodyHandlers.ofString());      OptionalLong contentLength = httpResponse             .headers().firstValueAsLong(HEADER_CONTENT_LENGTH);      return contentLength.orElse(0L); }<\/code><\/pre>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u043e\u0436\u0438\u0434\u0430\u0435\u043c\u0430\u044f \u0434\u043b\u0438\u043d\u0430 \u0444\u0430\u0439\u043b\u0430 \u0432 \u0431\u0430\u0439\u0442\u0430\u0445.<\/p>\n<h4>\u041c\u0435\u0442\u043e\u0434 byte[] download(final String uri, int chunkSize)<\/h4>\n<p>  \u041c\u043e\u0436\u0435\u043c \u043f\u0440\u0438\u0441\u0442\u0443\u043f\u0438\u0442\u044c \u043a \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044e \u043c\u0435\u0442\u043e\u0434\u0430 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u0438\u0440\u0443\u044e\u0449\u0435\u0433\u043e \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u0430 \u043f\u043e \u043f\u043e\u0440\u0446\u0438\u044f\u043c. \u0414\u043b\u044f \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u0430, \u0434\u043e\u0433\u043e\u0432\u043e\u0440\u0438\u043c\u0441\u044f \u0447\u0442\u043e \u0440\u0430\u0437\u043c\u0435\u0440 \u043f\u043e\u0440\u0446\u0438\u0439 \u0431\u0443\u0434\u0435\u0442 \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c\u0441\u044f \u0432\u0442\u043e\u0440\u044b\u043c \u0430\u0440\u0433\u0443\u043c\u0435\u043d\u0442\u043e\u043c \u0432 \u044d\u0442\u043e\u0442 \u043c\u0435\u0442\u043e\u0434. \u0425\u043e\u0442\u044f \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0431\u044b \u043f\u0440\u0438\u0434\u0443\u043c\u0430\u0442\u044c \u0443\u043c\u043d\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u0440\u0430\u0437\u043c\u0435\u0440\u0430 \u043f\u043e\u0440\u0446\u0438\u0439.<\/p>\n<p>  <b>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u0440\u0430\u0437\u043c\u0435\u0440 \u0444\u0430\u0439\u043b\u0430<\/b><\/p>\n<pre><code class=\"java\">final int expectedLength = (int) contentLength(uri);<\/code><\/pre>\n<p>  <b>\u041d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043c\u0435\u0449\u0435\u043d\u0438\u0435<\/b><\/p>\n<pre><code class=\"java\">int firstBytePos = 0;<\/code><\/pre>\n<p>  <b>\u041a\u043e\u043d\u0435\u0447\u043d\u043e\u0435 \u0441\u043c\u0435\u0449\u0435\u043d\u0438\u0435<\/b><\/p>\n<pre><code class=\"java\">int lastBytePos = chunkSize - 1;<\/code><\/pre>\n<p>  <b>\u0414\u0430\u043d\u043d\u044b\u0435<\/b><\/p>\n<p>  \u0421\u043a\u0430\u0447\u0430\u043d\u043d\u044b\u0435 \u0434\u0430\u043d\u043d\u044b\u0435 \u0437\u0430 \u043a\u0430\u0436\u0434\u0443\u044e \u0438\u0442\u0435\u0440\u0430\u0446\u0438\u044e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043d\u0430\u043a\u0430\u043f\u043b\u0438\u0432\u0430\u0442\u044c, \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0434\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043c\u0430\u0441\u0441\u0438\u0432, \u0440\u0430\u0437\u043c\u0435\u0440 \u043c\u0430\u0441\u0441\u0438\u0432\u0430 \u043d\u0430\u043c \u0443\u0436\u0435 \u0438\u0437\u0432\u0435\u0441\u0442\u0435\u043d.<\/p>\n<pre><code class=\"java\">byte[] downloadedBytes = new byte[expectedLength];<\/code><\/pre>\n<p>  <b>\u0420\u0430\u0437\u043c\u0435\u0440 \u0441\u043a\u0430\u0447\u0430\u043d\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445<\/b><\/p>\n<p>  \u0414\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043a \u0441\u0430\u043c\u043e\u043c\u0443 \u043c\u0430\u0441\u0441\u0438\u0432\u0443 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0442\u044c \u0441\u0443\u043c\u043c\u0430\u0440\u043d\u043e \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0434\u0430\u043d\u043d\u044b\u0445 \u0441\u043a\u0430\u0447\u0430\u043d\u043e. <\/p>\n<p>  \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u044d\u0442\u0443 \u0434\u043b\u0438\u043d\u0443 \u0431\u0443\u0434\u0435\u043c \u0441\u0447\u0438\u0442\u0430\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e.<\/p>\n<pre><code class=\"java\">int downloadedLength = 0;<\/code><\/pre>\n<p>  <\/p>\n<h4>\u0426\u0438\u043a\u043b \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u044f<\/h4>\n<p>  \u0423\u0441\u043b\u043e\u0432\u0438\u0435 \u0446\u0438\u043a\u043b\u0430 \u043f\u0440\u043e\u0441\u0442\u043e\u0435: \u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0430\u0435\u043c \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u0442\u044c \u043f\u043e\u043a\u0430 \u043d\u0435 \u0434\u043e\u0441\u0442\u0438\u0433\u043d\u0435\u043c \u043e\u0436\u0438\u0434\u0430\u0435\u043c\u043e\u0433\u043e \u0440\u0430\u0437\u043c\u0435\u0440\u0430. \u041f\u043e\u0441\u043b\u0435 \u0442\u043e\u0433\u043e \u043a\u0430\u043a \u0443\u0441\u043f\u0435\u0448\u043d\u043e \u0441\u043a\u0430\u0447\u0430\u043b\u0438 \u043e\u0447\u0435\u0440\u0435\u0434\u043d\u0443\u044e \u043f\u043e\u0440\u0446\u0438\u044e \u0434\u0430\u043d\u043d\u044b\u0445, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0435\u0433\u043e \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0432 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0438\u0440\u0443\u044e\u0449\u0438\u0439 \u043c\u0430\u0441\u0441\u0438\u0432, \u0432\u043e\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c\u0441\u044f \u0441\u0438\u0441\u0442\u0435\u043c\u043d\u044b\u043c \u043c\u0435\u0442\u043e\u0434\u043e\u043c \u043a\u043e\u043f\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043c\u0430\u0441\u0441\u0438\u0432\u0430 <code>System.arraycopy()<\/code>. \u0417\u0430\u0442\u0435\u043c \u043d\u0443\u0436\u043d\u043e \u0443\u0432\u0435\u043b\u0438\u0447\u0438\u0442\u044c \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u043d\u043d\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445 \u0438 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0434\u0438\u0430\u043f\u0430\u0437\u043e\u043d \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u0435\u043c\u044b\u0445 \u0434\u0430\u043d\u043d\u044b\u0445. \u041f\u0440\u0438 \u0443\u0432\u0435\u043b\u0438\u0447\u0435\u043d\u0438\u0438 \u0434\u0438\u0430\u043f\u0430\u0437\u043e\u043d\u0430 \u043d\u0443\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u043e\u0441\u0442\u043e\u0440\u043e\u0436\u043d\u0435\u0435, \u043d\u0435\u043b\u044c\u0437\u044f \u0432\u044b\u0445\u043e\u0434\u0438\u0442\u044c \u0437\u0430 \u043f\u0440\u0435\u0434\u0435\u043b\u044b. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0431\u0443\u0434\u0435\u043c \u0431\u0440\u0430\u0442\u044c \u043c\u0438\u043d\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0438\u0437 <code>Math.min(lastBytePos + chunkSize, expectedLength - 1)<\/code>.<\/p>\n<pre><code class=\"java\">private static final int HTTP_PARTIAL_CONTENT = 206;  while (downloadedLength &lt; expectedLength) {          Response response;          try {             response = download(uri, firstBytePos, lastBytePos);         }          try (response.inputStream) {             byte[] chunkedBytes = response.inputStream.readAllBytes();              downloadedLength += chunkedBytes.length;              if (isPartial(response)) {                 System.arraycopy(chunkedBytes, 0, downloadedBytes, firstBytePos,  chunkedBytes.length);                 firstBytePos = lastBytePos + 1;                 lastBytePos = Math.min(lastBytePos + chunkSize, expectedLength - 1);             }         }     }      return downloadedBytes; }  private boolean isPartial(Response response) {     return response.status == HTTP_PARTIAL_CONTENT; }<\/code><\/pre>\n<p>  \u041d\u0430 \u0432\u0438\u0434 \u0432\u0441\u0451 \u0445\u043e\u0440\u043e\u0448\u043e. \u0427\u0442\u043e \u043d\u0435 \u0442\u0430\u043a?<\/p>\n<p>  \u041a\u043e\u0433\u0434\u0430 \u043f\u0440\u0438 \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u0438 \u0438\u043b\u0438 \u0447\u0442\u0435\u043d\u0438\u0438 \u0447\u0442\u043e-\u0442\u043e \u043f\u043e\u0439\u0434\u0435\u0442 \u043d\u0435 \u0442\u0430\u043a, \u0431\u0440\u043e\u0441\u0438\u0442\u044c\u0441\u044f I\/O \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0438 \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u0435 \u043f\u0440\u0435\u043a\u0440\u0430\u0442\u0438\u0442\u044c\u0441\u044f. \u041e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u044e\u0442 fallback. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u043f\u0440\u043e\u0441\u0442\u043e\u0439 fallback \u0432\u0432\u0438\u0434\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u044b\u0445 \u043f\u043e\u043f\u044b\u0442\u043e\u043a.<\/p>\n<p>  \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u043f\u043e\u043b\u0435 \u0434\u043b\u044f \u0432\u0435\u0431-\u043a\u043b\u0438\u0435\u043d\u0442\u0430 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0449\u0438\u0439 \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043c\u044b\u0445 \u043f\u043e\u043f\u044b\u0442\u043e\u043a \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u044f \u0444\u0430\u0439\u043b\u0430.<\/p>\n<pre><code class=\"java\">private int maxAttempts;  public int maxAttempts() {     return maxAttempts; }  public void setMaxAttempts(int maxAttempts) {     this.maxAttempts = maxAttempts; }<\/code><\/pre>\n<p>  \u0411\u0443\u0434\u0435\u043c \u043b\u043e\u0432\u0438\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u043a\u0430\u0436\u0434\u043e\u0435 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0438 \u0438\u043d\u043a\u0440\u0435\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043b\u043e\u043a\u0430\u043b\u044c\u043d\u044b\u0439 \u0441\u0447\u0435\u0442\u0447\u0438\u043a \u043f\u043e\u043f\u044b\u0442\u043e\u043a. \u0426\u0438\u043a\u043b \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u044f \u0434\u043e\u043b\u0436\u0435\u043d \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c\u0441\u044f \u0435\u0441\u043b\u0438 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u044b\u0445 \u043f\u043e\u043f\u044b\u0442\u043e\u043a \u043f\u0440\u0435\u0432\u044b\u0448\u0430\u0435\u0442 \u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043c\u043e\u0435. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0434\u043e\u043f\u043e\u043b\u043d\u0438\u043c \u0443\u0441\u043b\u043e\u0432\u0438\u0435 \u0446\u0438\u043a\u043b\u0430.<\/p>\n<pre><code class=\"java\">private static final int DEFAULT_MAX_ATTEMPTS = 3;  int attempts = 1;  while (downloadedLength &lt; expectedLength &amp;&amp; attempts &lt; maxAttempts) {      Response response;      try {         response = download(uri, firstBytePos, lastBytePos);     } catch (IOException e) {         attempts++;         continue;     }      try (response.inputStream) {         byte[] chunkedBytes = response.inputStream.readAllBytes();          downloadedLength += chunkedBytes.length;          if (isPartial(response)) {             System.arraycopy(chunkedBytes, 0, downloadedBytes, firstBytePos, chunkedBytes.length);             firstBytePos = lastBytePos + 1;             lastBytePos = Math.min(lastBytePos + chunkSize, expectedLength - 1);         }     } catch (IOException e) {         attempts++;         continue;     }      attempts = 1; }<\/code><\/pre>\n<p>  \u0414\u043e\u043f\u043e\u043b\u043d\u0438\u043c \u043c\u0435\u0442\u043e\u0434 \u0435\u0449\u0435 \u043b\u043e\u0433\u0430\u043c\u0438. \u041e\u043a\u043e\u043d\u0447\u0430\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0442\u0430\u043a:<\/p>\n<pre><code class=\"java\">package art.aukhatov.http;  import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; import java.net.http.HttpClient; import java.net.http.HttpHeaders; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.time.Duration; import java.util.OptionalLong;  import static java.lang.String.format; import static java.lang.System.err; import static java.lang.System.out;  public class WebClient {  \tprivate static final String HEADER_RANGE = &quot;Range&quot;; \tprivate static final String RANGE_FORMAT = &quot;bytes=%d-%d&quot;; \tprivate static final String HEADER_CONTENT_LENGTH = &quot;content-length&quot;; \tprivate static final String HTTP_HEAD = &quot;HEAD&quot;; \tprivate static final int DEFAULT_MAX_ATTEMPTS = 3; \tprivate static final int HTTP_PARTIAL_CONTENT = 206;  \tprivate final HttpClient httpClient; \tprivate int maxAttempts;  \tpublic WebClient() { \t\tthis.httpClient = HttpClient.newBuilder() \t\t\t\t.connectTimeout(Duration.ofSeconds(10)) \t\t\t\t.build(); \t\tthis.maxAttempts = DEFAULT_MAX_ATTEMPTS; \t}  \tpublic WebClient(HttpClient httpClient) { \t\tthis.httpClient = httpClient; \t}  \tprivate long contentLength(final String uri) \t\t\tthrows URISyntaxException, IOException, InterruptedException {  \t\tHttpRequest headRequest = HttpRequest \t\t\t\t.newBuilder(new URI(uri)) \t\t\t\t.method(HTTP_HEAD, HttpRequest.BodyPublishers.noBody()) \t\t\t\t.version(HttpClient.Version.HTTP_2) \t\t\t\t.build();  \t\tHttpResponse&lt;String&gt; httpResponse = httpClient.send(headRequest, HttpResponse.BodyHandlers.ofString());  \t\tOptionalLong contentLength = httpResponse \t\t\t\t.headers().firstValueAsLong(HEADER_CONTENT_LENGTH);  \t\treturn contentLength.orElse(0L); \t}  \tpublic Response download(final String uri, int firstBytePos, int lastBytePos) \t\t\tthrows URISyntaxException, IOException, InterruptedException {  \t\tHttpRequest request = HttpRequest \t\t\t\t.newBuilder(new URI(uri)) \t\t\t\t.header(HEADER_RANGE, format(RANGE_FORMAT, firstBytePos, lastBytePos)) \t\t\t\t.GET() \t\t\t\t.version(HttpClient.Version.HTTP_2) \t\t\t\t.build();  \t\tHttpResponse&lt;InputStream&gt; response = httpClient.send(request, HttpResponse.BodyHandlers.ofInputStream());  \t\treturn new Response(new BufferedInputStream(response.body()), response.statusCode(), response.headers()); \t}  \tpublic byte[] download(final String uri, int chunkSize) \t\t\tthrows URISyntaxException, IOException, InterruptedException {  \t\tfinal int expectedLength = (int) contentLength(uri); \t\tint firstBytePos = 0; \t\tint lastBytePos = chunkSize - 1;  \t\tbyte[] downloadedBytes = new byte[expectedLength]; \t\tint downloadedLength = 0;  \t\tint attempts = 1;  \t\twhile (downloadedLength &lt; expectedLength &amp;&amp; attempts &lt; maxAttempts) {  \t\t\tResponse response;  \t\t\ttry { \t\t\t\tresponse = download(uri, firstBytePos, lastBytePos); \t\t\t} catch (IOException e) { \t\t\t\tattempts++; \t\t\t\terr.println(format(&quot;I\/O error has occurred. %s&quot;, e)); \t\t\t\tout.println(format(&quot;Going to do %d attempt&quot;, attempts)); \t\t\t\tcontinue; \t\t\t}  \t\t\ttry (response.inputStream) { \t\t\t\tbyte[] chunkedBytes = response.inputStream.readAllBytes();  \t\t\t\tdownloadedLength += chunkedBytes.length;  \t\t\t\tif (isPartial(response)) { \t\t\t\t\tSystem.arraycopy(chunkedBytes, 0, downloadedBytes, firstBytePos, chunkedBytes.length); \t\t\t\t\tfirstBytePos = lastBytePos + 1; \t\t\t\t\tlastBytePos = Math.min(lastBytePos + chunkSize, expectedLength - 1); \t\t\t\t} \t\t\t} catch (IOException e) { \t\t\t\tattempts++; \t\t\t\terr.println(format(&quot;I\/O error has occurred. %s&quot;, e)); \t\t\t\tout.println(format(&quot;Going to do %d attempt&quot;, attempts)); \t\t\t\tcontinue; \t\t\t}  \t\t\tattempts = 1; \/\/ reset attempts counter \t\t}  \t\tif (attempts &gt;= maxAttempts) { \t\t\terr.println(&quot;A file could not be downloaded. Number of attempts are exceeded.&quot;); \t\t}  \t\treturn downloadedBytes; \t}  \tprivate boolean isPartial(Response response) { \t\treturn response.status == HTTP_PARTIAL_CONTENT; \t}  \tpublic int maxAttempts() { \t\treturn maxAttempts; \t}  \tpublic void setMaxAttempts(int maxAttempts) { \t\tthis.maxAttempts = maxAttempts; \t}  \tpublic static class Response { \t\tfinal BufferedInputStream inputStream; \t\tfinal int status; \t\tfinal HttpHeaders headers;  \t\tpublic Response(BufferedInputStream inputStream, int status, HttpHeaders headers) { \t\t\tthis.inputStream = inputStream; \t\t\tthis.status = status; \t\t\tthis.headers = headers; \t\t} \t} }<\/code><\/pre>\n<p>  <\/p>\n<h2>\u0422\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435<\/h2>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043c\u043e\u0436\u0435\u043c \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0442\u0435\u0441\u0442 \u043d\u0430 Junit 5 \u0434\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u044f \u0444\u0430\u0439\u043b\u0430. \u0414\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u0440\u0430 \u0432\u043e\u0437\u044c\u043c\u0435\u043c \u0440\u0430\u043d\u0434\u043e\u043c\u043d\u044b\u0439 \u0444\u0430\u0439\u043b \u0432 \u0418\u043d\u0442\u0435\u0440\u043d\u0435\u0442\u0435 \u0438\u0437 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u044b\u0445 \u0431\u0435\u0437 \u0430\u0443\u0442\u0435\u043d\u0442\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u0438: <a href=\"https:\/\/file-examples.com\/wp-content\/uploads\/2017\/10\/file-example_PDF_1MB.pdf\" rel=\"nofollow\">file-examples.com\/wp-content\/uploads\/2017\/10\/file-example_PDF_1MB.pdf<\/a><\/p>\n<p>  \u0421\u043e\u0445\u0440\u0430\u043d\u0438\u043c \u0444\u0430\u0439\u043b \u0432\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e. \u0418 \u043f\u0440\u043e\u0432\u0435\u0440\u0438\u043c \u0440\u0430\u0437\u043c\u0435\u0440 \u0444\u0430\u0439\u043b\u0430.<\/p>\n<pre><code class=\"java\">class WebClientTest {  \t@Test \tvoid downloadByChunk() throws IOException, URISyntaxException, InterruptedException { \t\tWebClient fd = new WebClient(); \t\tbyte[] data = fd.download(&quot;https:\/\/file-examples.com\/wp-content\/uploads\/2017\/10\/file-example_PDF_1MB.pdf&quot;, 262_144); \t\tfinal String downloadedFilePath = System.getProperty(&quot;java.io.tmpdir&quot;) + &quot;sample.pdf&quot;; \t\tSystem.out.println(&quot;File has downloaded to &quot; + downloadedFilePath);  \t\tPath path = Paths.get(downloadedFilePath);  \t\ttry (OutputStream outputStream = Files.newOutputStream(path)) { \t\t\toutputStream.write(data); \t\t\toutputStream.flush();  \t\t\tassertEquals(1_042_157, Files.readAllBytes(Paths.get(downloadedFilePath)).length);  \t\t\tFiles.delete(path); \t\t} \t} }<\/code><\/pre>\n<p>  <\/p>\n<h2>\u0417\u0430\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435<\/h2>\n<p>  \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u0431\u044b\u043b\u043e \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u043d\u043e \u043a\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u0430 \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u0437\u0430\u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u043f\u043e\u0440\u0446\u0438\u044f\u043c\u0438. \u0414\u043b\u044f \u0431\u043e\u043b\u044c\u0448\u0435\u0439 \u0433\u0438\u0431\u043a\u043e\u0441\u0442\u0438 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u0434\u0443\u043c\u0430\u0442\u044c \u043e \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u043e\u043c \u0440\u0430\u0437\u043c\u0435\u0440\u0435 \u043f\u043e\u0440\u0446\u0438\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0440\u0430\u0441\u0448\u0438\u0440\u044f\u0435\u0442\u0441\u044f \u0438 \u0441\u0443\u0436\u0430\u0435\u0442\u0441\u044f \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u044f \u0441\u0435\u0440\u0432\u0435\u0440\u0430. \u0422\u0430\u043a\u0436\u0435 \u0434\u043e \u043a\u043e\u043d\u0446\u0430 \u043d\u0435 \u043f\u043e\u043a\u0440\u044b\u0442\u044b \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u044b\u0435 \u0438\u0441\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0436\u043d\u043e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0438\u043d\u0430\u0447\u0435. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u043e\u0448\u0438\u0431\u043a\u0430 <code>401 Unauthorized<\/code> \u0438\u043b\u0438 <code>500 Internal Server Error<\/code>.<\/p>\n<p>  \u0412 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u0434\u043e\u043c\u0430\u0448\u043d\u0435\u0433\u043e \u0437\u0430\u0434\u0430\u043d\u0438\u044f \u043a\u043e\u0434 \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u043f\u0435\u0440\u0432\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0435 \u0440\u0430\u0437\u043c\u0435\u0440\u0430 \u0444\u0430\u0439\u043b\u0430. \u0422\u0430\u043a\u0436\u0435 \u043c\u043e\u0436\u043d\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043f\u0440\u0438\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0443 \u0438 \u0432\u043e\u0437\u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435.<\/p><\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/post\/503984\/\"> https:\/\/habr.com\/ru\/post\/503984\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"\n<div class=\"post__text post__text-html post__text_v1\" id=\"post-content-body\" data-io-article-url=\"https:\/\/habr.com\/ru\/post\/503984\/\">\n<div style=\"text-align:center;\"><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/nk\/rg\/wy\/nkrgwyimwne_fs4v1fmhxwzbjr4.png\"><\/div>\n<p>  \u0418\u043d\u043e\u0433\u0434\u0430 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u0442\u044c \u0444\u0430\u0439\u043b \u043f\u043e\u0440\u0446\u0438\u044f\u043c\u0438. \u041f\u0440\u0438\u0447\u0438\u043d\u044b \u0431\u044b\u0432\u0430\u044e\u0442 \u0440\u0430\u0437\u043d\u044b\u0435, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u201c\u0431\u043e\u043b\u044c\u0448\u043e\u0439\u201d \u043e\u0431\u044a\u0435\u043c \u0444\u0430\u0439\u043b\u0430, \u0448\u0438\u0440\u0438\u043d\u0430 \u043a\u0430\u043d\u0430\u043b\u0430 \u043d\u0435 \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u0430 \u0438\u043b\u0438 \u0441\u0435\u0440\u0432\u0435\u0440 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0438\u0432\u0430\u0435\u0442 \u043e\u0431\u044a\u0435\u043c \u0434\u0430\u043d\u043d\u044b\u0445 \u0434\u043b\u044f \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u044f.<\/p>\n<p>  \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u043e\u043f\u0438\u0448\u0443 \u043a\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u0435 \u0444\u0430\u0439\u043b\u0430 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u0438\u043c\u0438 \u043f\u043e\u0440\u0446\u0438\u044f\u043c\u0438 \u043d\u0430 \u044f\u0437\u044b\u043a\u0435 Java \u043f\u043e \u043f\u0440\u043e\u0442\u043e\u043a\u043e\u043b\u0443 HTTP.<\/p>\n<h2>\u041e\u0431 HTTP<\/h2>\n<p>  \u0414\u043b\u044f \u0442\u0430\u043a\u0438\u0445 \u0446\u0435\u043b\u0435\u0439 HTTP \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a <b><code>Range<\/code><\/b> \u0434\u043b\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u0430. \u0412 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0434\u0438\u0430\u043f\u0430\u0437\u043e\u043d \u0431\u0430\u0439\u0442\u043e\u0432 \u0434\u043b\u044f \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u044f. \u0417\u0430\u0433\u043e\u043b\u043e\u0432\u043e\u043a <code>Range<\/code> \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043a \u0442\u0435\u043b\u0443 \u0437\u0430\u043f\u0440\u043e\u0441\u0430, \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0438 \u0441\u044e\u0434\u0430 \u043d\u0435 \u0432\u0445\u043e\u0434\u044f\u0442.<\/p>\n<p>  \u0421\u043f\u0435\u0446\u0438\u0444\u0438\u043a\u0430\u0446\u0438\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u0444\u043e\u0440\u043c\u0430\u0442\u044b \u0443\u043a\u0430\u0437\u0430\u043d\u0438\u044f \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u0437\u0430\u0433\u043e\u043b\u043e\u0432\u043a\u0430:<\/p>\n<pre><code class=\"markdown\">Range: bytes=first-byte-pos &quot;-&quot; [last-byte-pos]<\/code><\/pre>\n<p>  <b>first-byte-pos<\/b> \u2014 \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0435 \u0441\u043c\u0435\u0449\u0435\u043d\u0438\u0435 \u0431\u0430\u0439\u0442\u0430 \u0441 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043d\u0430\u0447\u0430\u0442\u044c (\u043f\u0440\u043e\u0434\u043e\u043b\u0436\u0438\u0442\u044c) \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u043d\u0438\u0435, \u043e\u043d\u043e \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u0435 \u043b\u0438\u0431\u043e \u0440\u0430\u0432\u043d\u043e 0, \u0438 \u043c\u0435\u043d\u044c\u0448\u0435 \u043b\u0438\u0431\u043e \u0440\u0430\u0432\u043d\u043e last-byte-pos;<\/p>\n<p>  <b>last-byte-pos<\/b> \u2014 \u043a\u043e\u043d\u0435\u0447\u043d\u043e\u0435 \u0441\u043c\u0435\u0449\u0435\u043d\u0438\u0435 \u0431\u0430\u0439\u0442\u0430 \u0434\u043e \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0441\u043a\u0430\u0447\u0430\u0442\u044c \u0444\u0430\u0439\u043b, \u043e\u043d\u043e \u0434\u043e\u043b\u0436\u043d\u043e \u0431\u044b\u0442\u044c \u0431\u043e\u043b\u044c\u0448\u0435 \u043b\u0438\u0431\u043e \u0440\u0430\u0432\u043d\u043e first-byte-pos \u0438 \u043f\u0440\u0438 \u044d\u0442\u043e\u043c \u043c\u0435\u043d\u044c\u0448\u0435 \u043b\u0438\u0431\u043e \u0440\u0430\u0432\u043d\u043e \u0441\u043a\u0430\u0447\u0438\u0432\u0430\u0435\u043c\u043e\u043c\u0443 \u0440\u0430\u0437\u043c\u0435\u0440\u0443 \u0444\u0430\u0439\u043b\u0430 \u043c\u0438\u043d\u0443\u0441 \u043e\u0434\u0438\u043d (\u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u044d\u0442\u043e \u0441\u043c\u0435\u0449\u0435\u043d\u0438\u0435, \u0442\u043e \u0435\u0441\u0442\u044c \u0438\u043d\u0434\u0435\u043a\u0441 \u0432 \u043c\u0430\u0441\u0441\u0438\u0432\u0435 \u0431\u0430\u0439\u0442\u043e\u0432).  <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-306600","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/306600","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=306600"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/306600\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=306600"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=306600"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=306600"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}