网站维护进不去怎么办网站服务器ip
网站维护进不去怎么办,网站服务器ip,9951026企业邮箱888,江苏城嘉建设工程有限公司网站客户端缓存是万维网的基础之一。 服务器应告知客户端资源的有效性#xff0c;客户端应尽可能快地对其进行缓存。 如我们所见#xff0c;如果不缓存Web#xff0c;将会非常慢。 只需在任何网站上Ctrl F5并将其与普通F5进行比较-后者就会更快#xff0c;因为它使用了已缓存的… 客户端缓存是万维网的基础之一。 服务器应告知客户端资源的有效性客户端应尽可能快地对其进行缓存。 如我们所见如果不缓存Web将会非常慢。 只需在任何网站上Ctrl F5并将其与普通F5进行比较-后者就会更快因为它使用了已缓存的资源。 缓存对于下载也很重要。 如果我们已经获取了几兆字节的数据并且它们没有改变则通过网络推送它们是非常浪费的。 使用 HTTP ETag标头可用于避免重复下载客户端已有的资源。 服务器与第一响应服务器一起返回ETag标头该标头通常是文件内容的哈希值。 客户端可以保留ETag并在以后请求相同资源时将其发送在If-None-Match请求标头中。 如果在此期间未更改则服务器可以简单地返回304 Not Modified响应。 让我们从对ETag支持的集成测试开始 def should send file if ETag not present() {expect:mockMvc.perform(get(/download/ FileExamples.TXT_FILE_UUID)).andExpect(status().isOk())}def should send file if ETag present but not matching() {expect:mockMvc.perform(get(/download/ FileExamples.TXT_FILE_UUID).header(IF_NONE_MATCH, WHATEVER)).andExpect(status().isOk())
}def should not send file if ETag matches content() {given:String etag FileExamples.TXT_FILE.getEtag()expect:mockMvc.perform(get(/download/ FileExamples.TXT_FILE_UUID).header(IF_NONE_MATCH, etag)).andExpect(status().isNotModified()).andExpect(header().string(ETAG, etag))
} 有趣的是Spring框架中内置了ShallowEtagHeaderFilter 。 安装它会使所有测试通过包括最后一个测试 WebAppConfiguration
ContextConfiguration(classes [MainApplication])
ActiveProfiles(test)
class DownloadControllerSpec extends Specification {private MockMvc mockMvcAutowiredpublic void setWebApplicationContext(WebApplicationContext wac) {mockMvc MockMvcBuilders.webAppContextSetup(wac).addFilter(new Sha512ShallowEtagHeaderFilter(), /download/*).build()}//tests...} 我实际上插入了使用SHA-512而不是默认MD5的自己的Sha512ShallowEtagHeaderFilter 。 同样由于某种原因默认实现在哈希值前面加上0 public class ShallowEtagHeaderFilter {protected String generateETagHeaderValue(byte[] bytes) {StringBuilder builder new StringBuilder(\0);DigestUtils.appendMd5DigestAsHex(bytes, builder);builder.append();return builder.toString();}//...
} 与 public class Sha512ShallowEtagHeaderFilter extends ShallowEtagHeaderFilter {Overrideprotected String generateETagHeaderValue(byte[] bytes) {final HashCode hash Hashing.sha512().hashBytes(bytes);return \ hash \;}
} 不幸的是我们无法使用内置过滤器因为它们必须首先完全读取响应主体才能计算ETag 。 这基本上关闭了上一篇文章中介绍的主体流传输–整个响应都存储在内存中。 我们必须自己实现ETag功能。 从技术上讲 If-None-Match可以包含多个ETag值。 但是谷歌浏览器和ShallowEtagHeaderFilter支持它因此我们也将跳过它。 为了控制响应头我们现在返回ResponseEntityResource RequestMapping(method GET, value /{uuid})
public ResponseEntityResource download(PathVariable UUID uuid,RequestHeader(IF_NONE_MATCH) OptionalString requestEtagOpt) {return storage.findFile(uuid).map(pointer - prepareResponse(pointer, requestEtagOpt)).orElseGet(() - new ResponseEntity(NOT_FOUND));
}private ResponseEntityResource prepareResponse(FilePointer filePointer, OptionalString requestEtagOpt) {return requestEtagOpt.filter(filePointer::matchesEtag).map(this::notModified).orElseGet(() - serveDownload(filePointer));
}private ResponseEntityResource notModified(String etag) {log.trace(Cached on client side {}, returning 304, etag);return ResponseEntity.status(NOT_MODIFIED).eTag(etag).body(null);
}private ResponseEntityResource serveDownload(FilePointer filePointer) {log.debug(Serving {}, filePointer);final InputStream inputStream filePointer.open();final InputStreamResource resource new InputStreamResource(inputStream);return ResponseEntity.status(OK).eTag(filePointer.getEtag()).body(resource);
} 该过程由可选的requestEtagOpt控制。 如果存在并且与客户端发送的内容匹配则返回304。否则照常发送200 OK。 本示例中介绍的FilePointer新方法如下所示 import com.google.common.hash.HashCode;
import com.google.common.hash.Hashing;
import com.google.common.io.Files;public class FileSystemPointer implements FilePointer {private final File target;private final HashCode tag;public FileSystemPointer(File target) {try {this.target target;this.tag Files.hash(target, Hashing.sha512());} catch (IOException e) {throw new IllegalArgumentException(e);}}Overridepublic InputStream open() {try {return new BufferedInputStream(new FileInputStream(target));} catch (FileNotFoundException e) {throw new IllegalArgumentException(e);}}Overridepublic String getEtag() {return \ tag \;}Overridepublic boolean matchesEtag(String requestEtag) {return getEtag().equals(requestEtag);}
} 在这里您将看到FileSystemPointer实现该实现直接从文件系统读取文件。 关键部分是缓存标记而不是在每次请求时都重新计算标记。 上面的实现的行为符合预期例如Web浏览器不会再次下载资源。 3.使用 与ETag和If-None-Match标头类似还有Last-Modified和If-Modified-Since 。 我猜它们很容易解释第一个服务器返回Last-Modified响应标头指示给定资源的最后修改时间 duh 。 客户端缓存此时间戳并将其与后续请求一起传递给If-Modified-Since请求标头中的相同资源。 如果同时未更改资源则服务器将响应304从而节省带宽。 这是一个后备机制同时实现ETag和Last-Modified是一个很好的实践。 让我们从集成测试开始 def should not return file if wasn\t modified recently() {given:Instant lastModified FileExamples.TXT_FILE.getLastModified()String dateHeader toDateHeader(lastModified)expect:mockMvc.perform(get(/download/ FileExamples.TXT_FILE_UUID).header(IF_MODIFIED_SINCE, dateHeader)).andExpect(status().isNotModified())
}def should not return file if server has older version than the client() {given:Instant lastModifiedLaterThanServer FileExamples.TXT_FILE.getLastModified().plusSeconds(60)String dateHeader toDateHeader(lastModifiedLaterThanServer)expect:mockMvc.perform(get(/download/ FileExamples.TXT_FILE_UUID).header(IF_MODIFIED_SINCE, dateHeader)).andExpect(status().isNotModified())
}def should return file if was modified after last retrieval() {given:Instant lastModifiedRecently FileExamples.TXT_FILE.getLastModified().minusSeconds(60)String dateHeader toDateHeader(lastModifiedRecently)expect:mockMvc.perform(get(/download/ FileExamples.TXT_FILE_UUID).header(IF_MODIFIED_SINCE, dateHeader)).andExpect(status().isOk())
}private static String toDateHeader(Instant lastModified) {ZonedDateTime dateTime ZonedDateTime.ofInstant(lastModified, ZoneOffset.UTC)DateTimeFormatter.RFC_1123_DATE_TIME.format(dateTime)
} 并执行 RequestMapping(method GET, value /{uuid})
public ResponseEntityResource download(PathVariable UUID uuid,RequestHeader(IF_NONE_MATCH) OptionalString requestEtagOpt,RequestHeader(IF_MODIFIED_SINCE) OptionalDate ifModifiedSinceOpt) {return storage.findFile(uuid).map(pointer - prepareResponse(pointer,requestEtagOpt,ifModifiedSinceOpt.map(Date::toInstant))).orElseGet(() - new ResponseEntity(NOT_FOUND));
}private ResponseEntityResource prepareResponse(FilePointer filePointer, OptionalString requestEtagOpt, OptionalInstant ifModifiedSinceOpt) {if (requestEtagOpt.isPresent()) {final String requestEtag requestEtagOpt.get();if (filePointer.matchesEtag(requestEtag)) {return notModified(filePointer);}}if (ifModifiedSinceOpt.isPresent()) {final Instant isModifiedSince ifModifiedSinceOpt.get();if (filePointer.modifiedAfter(isModifiedSince)) {return notModified(filePointer);}}return serveDownload(filePointer);
}private ResponseEntityResource serveDownload(FilePointer filePointer) {log.debug(Serving {}, filePointer);final InputStream inputStream filePointer.open();final InputStreamResource resource new InputStreamResource(inputStream);return response(filePointer, OK, resource);
}private ResponseEntityResource notModified(FilePointer filePointer) {log.trace(Cached on client side {}, returning 304, filePointer);return response(filePointer, NOT_MODIFIED, null);
}private ResponseEntityResource response(FilePointer filePointer, HttpStatus status, Resource body) {return ResponseEntity.status(status).eTag(filePointer.getEtag()).lastModified(filePointer.getLastModified().toEpochMilli()).body(body);
} 可悲的是习惯上使用Optional不再看起来不错所以我坚持使用isPresent() 。 我们同时检查If-Modified-Since和If-None-Match 。 如果两者都不匹配我们将照常提供文件。 只是为了让您了解这些标头的工作方式让我们执行一些端到端测试。 第一个要求 GET /download/4a8883b6-ead6-4b9e-8979-85f9846cab4b HTTP/1.1...HTTP/1.1 200 OKETag: 8b97c678a7f1d2e0af...921228d8eLast-Modified: Sun, 17 May 2015 15:45:26 GMT... 带有ETag后续请求已缩短 GET /download/4a8883b6-ead6-4b9e-8979-85f9846cab4b HTTP/1.1If-None-Match: 8b97c678a7f1d2e0af...921228d8e...HTTP/1.1 304 Not ModifiedETag: 8b97c678a7f1d2e0af...921228d8eLast-Modified: Sun, 17 May 2015 15:45:26 GMT... 如果我们的客户仅支持Last-Modified GET /download/4a8883b6-ead6-4b9e-8979-85f9846cab4b HTTP/1.1If-Modified-Since: Tue, 19 May 2015 06:59:55 GMT...HTTP/1.1 304 Not ModifiedETag: 8b97c678a7f1d2e0af9cda473b36c21f1b68e35b93fec2eb5c38d182c7e8f43a069885ec56e127c2588f9495011fd8ce032825b6d3136df7adbaa1f921228d8eLast-Modified: Sun, 17 May 2015 15:45:26 GMT 有许多内置工具例如过滤器可以为您处理缓存。 但是如果您需要确保在服务器端流传输文件而不是对其进行预先缓冲则需要格外小心。 编写下载服务器 第一部分始终流式传输永远不要完全保留在内存中 第二部分标头Last-ModifiedETag和If-None-Match 第三部分标头内容长度和范围 第四部分有效地实现HEAD操作 第五部分油门下载速度 第六部分描述您发送的内容内容类型等 这些文章中开发的示例应用程序可在GitHub上找到。 翻译自: https://www.javacodegeeks.com/2015/06/writing-a-download-server-part-ii-headers-last-modified-etag-and-if-none-match.html
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/91946.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!