java gzip rest_RestTemplate与Gzip压缩

Gzip 是一种压缩算法,服务器经常通过这个算法来压缩响应体,再响应给客户端,从而减少数据体积,提高传输速度。客户端再通过Gzip解压缩,获取到原始的数据。因为需要压缩计算,所以会耗费额外的CPU资源。

Gzip 与 HttpHeader

对于压缩,这个行为来说,客户端与服务器都要经过协商。只有使用了同一种压缩算法,才能正确的解码出数据。http协议中定义了相关的header

Content-Encoding

是一个实体消息首部,用于对特定媒体类型的数据进行压缩。当这个首部出现的时候,它的值表示消息主体进行了何种方式的内容编码转换。这个消息首部用来告知客户端应该怎样解码才能获取在 Content-Type 中标示的媒体类型内容。

一般建议对数据尽可能地进行压缩,因此才有了这个消息首部的出现。不过对于特定类型的文件来说,比如jpeg图片文件,已经是进行过压缩的了。有时候再次进行额外的压缩无助于负载体积的减小,反而有可能会使其增大。

客户端和服务器都可以使用,表示body中的数据采用了什么编码(压缩算法)

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Content-Encoding

Accept-Encoding

HTTP 请求头 Accept-Encoding 会将客户端能够理解的内容编码方式——通常是某种压缩算法——进行通知(给服务端)。通过内容协商的方式,服务端会选择一个客户端提议的方式,使用并在响应头 Content-Encoding 中通知客户端该选择。

即使客户端和服务器都支持相同的压缩算法,在 identity 指令可以被接受的情况下,服务器也可以选择对响应主体不进行压缩。导致这种情况出现的两种常见的情形是:

要发送的数据已经经过压缩,再次进行压缩不会导致被传输的数据量更小。一些图像格式的文件会存在这种情况;

服务器超载,无法承受压缩需求导致的计算开销。通常,如果服务器使用超过80%的计算能力,微软建议不要压缩。

只要 identity —— 表示不需要进行任何编码——没有被明确禁止使用(通过 identity;q=0 指令或是 *;q=0 而没有为 identity 明确指定权重值),则服务器禁止返回表示客户端错误的 406 Not Acceptable 响应。

一般是客户端使用,表示给服务器说明,客户端支持的压缩算法列表。服务从中选择一个对响应体进行压缩。

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Accept-Encoding

演示一个手动编/解码的Demo

服务端手动进行Gzip编码

import java.io.ByteArrayOutputStream;

import java.io.IOException;

import java.nio.charset.StandardCharsets;

import java.util.zip.GZIPOutputStream;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.http.HttpHeaders;

import org.springframework.http.MediaType;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

@RestController

@RequestMapping("/test")

public class TestController {

private static final Logger LOGGER = LoggerFactory.getLogger(TestController.class);

@GetMapping

public void test(HttpServletRequest request, HttpServletResponse reponse) throws IOException {

// 响应体

String content = "昔日龌龊不足夸,今朝放荡思无涯。春风得意马蹄疾,一日看尽长安花。";

String acceptEncooding = request.getHeader(HttpHeaders.ACCEPT_ENCODING);

/**

* 获取客户端支持的编码格式,程序可以根据这个header判断是否要对响应体进行编码

*/

LOGGER.info(acceptEncooding);

// 响应体使用 gzip 编码

reponse.setHeader(HttpHeaders.CONTENT_ENCODING, "gzip");

// 响应体类型是字符串

reponse.setContentType(MediaType.TEXT_PLAIN_VALUE);

// 编码是utf-8

reponse.setCharacterEncoding(StandardCharsets.UTF_8.displayName());

// Gzip压缩后响应

reponse.getOutputStream().write(gZip(content.getBytes(StandardCharsets.UTF_8)));

}

/**

* Gzip压缩数据

* @param data

* @return

* @throws IOException

*/

public static byte[] gZip(byte[] data) throws IOException {

ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();

try (GZIPOutputStream gzipOutputStream = new GZIPOutputStream(byteArrayOutputStream)) {

gzipOutputStream.write(data);

gzipOutputStream.finish();

return byteArrayOutputStream.toByteArray();

}

}

}

客户端手动解码

import java.io.ByteArrayInputStream;

import java.io.ByteArrayOutputStream;

import java.io.IOException;

import java.io.InputStream;

import java.nio.charset.StandardCharsets;

import java.util.zip.GZIPInputStream;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.http.HttpEntity;

import org.springframework.http.HttpHeaders;

import org.springframework.http.HttpMethod;

import org.springframework.http.MediaType;

import org.springframework.http.ResponseEntity;

import org.springframework.web.client.RestTemplate;

public class Main {

public static final Logger LOGGER = LoggerFactory.getLogger(Main.class);

public static void main(String[] args) throws Exception {

RestTemplate restTemplate = new RestTemplate();

HttpHeaders httpHeaders = new HttpHeaders();

// Accept 表示客户端支持什么格式的响应体

httpHeaders.set(HttpHeaders.ACCEPT, MediaType.TEXT_PLAIN_VALUE);

// Accept-Encoding 头,表示客户端接收gzip格式的压缩

httpHeaders.set(HttpHeaders.ACCEPT_ENCODING, "gzip");

ResponseEntity responseEntity = restTemplate.exchange("http://localhost/test", HttpMethod.GET, new HttpEntity<>(httpHeaders), byte[].class);

if (!responseEntity.getStatusCode().is2xxSuccessful()) {

// TODO 非200响应

}

// 获取服务器响应体编码

String contentEncoding = responseEntity.getHeaders().getFirst(HttpHeaders.CONTENT_ENCODING);

if ("gzip".equals(contentEncoding)) { // gzip编码

// gzip解压服务器的响应体

byte[] data = unGZip(new ByteArrayInputStream(responseEntity.getBody()));

LOGGER.info(new String(data, StandardCharsets.UTF_8));

} else {

// TODO 其他的编码

}

}

/**

* Gzip解压缩

* @param inputStream

* @return

* @throws IOException

*/

public static byte[] unGZip(InputStream inputStream) throws IOException {

ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();

try (GZIPInputStream gzipInputStream = new GZIPInputStream(inputStream)) {

byte[] buf = new byte[4096];

int len = -1;

while ((len = gzipInputStream.read(buf, 0, buf.length)) != -1) {

byteArrayOutputStream.write(buf, 0, len);

}

return byteArrayOutputStream.toByteArray();

} finally {

byteArrayOutputStream.close();

}

}

}

客户端执行日志,准确的解码了响应体

20:36:54.129 [main] INFO - 昔日龌龊不足夸,今朝放荡思无涯。春风得意马蹄疾,一日看尽长安花。

SpringBoot的响应体压缩配置

实际上,并不需要自己手动去写这种响应体的压缩代码。springboot提供了相关的配置。

SpringBoot2开启响应压缩

最后

使用RestTemplate请求文本数据接口,发现解码后的字符串是乱码。此时就可以怀疑是不是服务器响应了压缩后的数据。解决这个问题,先尝试移除Accept-Encoding请求头,告诉服务器,客户端不需要压缩响应体。如果服务器还是响应压缩后的数据,尝试读取服务器的Content-Encoding头,根据服务器的压缩编码,自己再进行解压缩。

原文: https://springboot.io/t/topic/2868

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/567930.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

RNN入门

雷锋网 AI科技评论按&#xff1a;本文作者何之源&#xff0c;原文载于知乎专栏AI Insight&#xff0c;雷锋网(公众号&#xff1a;雷锋网) AI科技评论获其授权发布。 上周写的文章《完全图解RNN、RNN变体、Seq2Seq、Attention机制》介绍了一下RNN的几种结构&#xff0c;今天就来…

Java二进制小数表示_《Java编程的逻辑》笔记9--小数的二进制表示

小数计算为什么会出错&#xff1f;简要答案实际上&#xff0c;不是运算本身会出错&#xff0c;而是计算机根本就不能精确的表示很多数&#xff0c;比如0.1这个数。计算机是用一种二进制格式存储小数的&#xff0c;这个二进制格式不能精确表示0.1&#xff0c;它只能表示一个非常…

『TensorFlow』模型保存和载入方法汇总

一、TensorFlow常规模型加载方法 保存模型 tf.train.Saver()类&#xff0c;.save(sess, ckpt文件目录)方法 参数名称功能说明默认值var_listSaver中存储变量集合全局变量集合reshape加载时是否恢复变量形状Truesharded是否将变量轮循放在所有设备上Truemax_to_keep保留最近检…

STL13-list容器(链表)

链表是由一系列的结点组成&#xff0c;结点包括两个域&#xff1a;一个数据域&#xff0c;一个指针域 1、链表内存是非连续的&#xff0c;添加删除元素效率较高&#xff0c;时间复杂度都是常数项&#xff0c;不需要移动元素 2、链表只有在需要的时候才会分配内存 3、链表只要…

java调用el_[Java教程][javaEE] EL表达式调用java方法

[Java教程][javaEE] EL表达式调用java方法0 2016-07-03 18:00:031.新建个类&#xff0c;类里面定义静态方法package com.tsh.utils;import java.net.URLEncoder;public class ELFunc { public static String urlEncode(String str){ return URLEncoder.encode(str); }}2.在WEB-…

Leedcode8-reorder-list

#include<iostream> #include<vector> using namespace std; //Definition for singly-linked list. /*Given a singly linked list L : L 0→L 1→…→L n - 1→L n, reorder it to : L 0→L n →L 1→L n - 1→L 2→L n - 2→…*/ struct ListNode {int val;List…

java设计是什么软件下载_用Java设计下载软件

用Java设计下载软件HTTP 协议的简介HTTP协议是一种超文本传输协议(Hypertext Transfer Protocol)&#xff0c;工作于网络应用层&#xff0c;自1990年起广泛应用于WWW 的全球信息服务&#xff0c;HTTP协议的具体说明可以在网上查阅RFC2518、RFC2616等文档。HTTP 协议老的标准是H…

php 前往页面,PHP实现网页截图?

如何使用PHP实现网页截图PHP实现网页截图是一个在日常开发中不常见的需求&#xff0c;但是如果实现还是非常有意思的。目前业界有很多成熟的方案&#xff0c;下面我推荐使用一个很稳定的第三方服务来直接实现&#xff0c;该服务有如下特点&#xff1a;支持多线路支持登录截图支…

Leedcode9-linked-list-cycle-i

判断链表是不是循环链表 #include<iostream> #include<vector> using namespace std; /* Given a linked list, determine if it has a cycle in it. Follow up: Can you solve it without using extra space?*/ struct ListNode {int val;ListNode *next;ListNo…

Leedcode10-linked-list-cycle-ii

判断是不是循环链表&#xff0c;如果是&#xff0c;返回它的第一个结点 首先判断&#xff0c;判断完之后&#xff0c;遍历循环链表&#xff0c;将它的指针域置为空&#xff0c;则循环到链表的第一个结点时&#xff0c;由于指针域为空&#xff0c;返回 #include<iostream&g…

STL14-set/multiset容器

set只有一个方法就是insert #include<iostream> #include<set> //set和multiset是一个头文件 //set内部实现机制 红黑色&#xff08;平衡二叉树的一种&#xff09; //关联式容器 //set不允许有重复元素 //multiset运行有重复元素 //容器查找效率高 //容器根据元素的…

普通的java类型是指,String是一个很普通的类 - Java那些事儿

上一篇我们讲了Java中的数组&#xff0c;其实是为本章的内容做准备的&#xff0c;String这个类是我们在写Java代码中用得最多的一个类&#xff0c;没有之一&#xff0c;今天我们就讲讲它&#xff0c;我们打开String这个类的源码&#xff1a;声明了一个char[]数组&#xff0c;变…

STL15-map/multimap容器

map的key值不可以重复 multimap的key值可以重复 #if 1 #include<iostream> #include<map> using namespace std; //初始化 void test01() {//map容器参数 第一个参数key的类型 第二个参数value类型map<int, int> mymap;//插入元素 pair.first key值 pair.se…

php nginx日志分析,如何通过NGINX的log日志来分析网站的访问情况,试试这些命令...

想知道你的网站每天的访问情况吗&#xff1f;有多少人访问了&#xff1f;访问最多的页面是哪个&#xff1f;哪个时段访问的人最多&#xff1f;哪个地方访问的最多&#xff1f;每秒有多少请求&#xff1f;很好奇吧&#xff0c;只要你是使用了nginx进行请求抓发&#xff0c;那么就…

ajax获取表单php,Yii2基于Ajax自动获取表单数据的方法

本文实例讲述了Yii2基于Ajax自动获取表单数据的方法。分享给大家供大家参考&#xff0c;具体如下&#xff1a;这里有两张表&#xff0c;表结构如下&#xff0c;locations表存放的省份和邮编等信息&#xff0c;两张表的model和curd均使用gii生成yii2advanced.customers表custome…

php response响应,9. 响应 (Response)

## 为什么单独创建一个Response?跟为什么要单独创建一个Request 一样。原因: 可以管理如: 在 swoole 不应该用 echo, 因为 swoole 是 cli 运行,只会输出在命令行。必须 只有一个地方能 输出响应 就是此篇的功能确保有 集中控制权 是非常重要 !(后面代码有 echo 都是不规范的, …

php带来互联网的影响,网络对我们的影响有哪些?

影响有&#xff1a;1、丰富了我们的业余生活&#xff1b;2、降低了获取知识的成本&#xff0c;降低了提升工作的能力的成本&#xff0c;提高了工作的效率&#xff0c;可以快速建立良好的人脉关系&#xff1b;3、让购物变得更加简单便捷&#xff1b;4、朋友间深度沟通与交流越来…

STL17-函数对象

仿函数&#xff1a; #include<iostream> #include<vector> #include<algorithm> using namespace std; //仿函数&#xff08;函数对象&#xff09;重载“&#xff08;&#xff09;”操作符 使类对象可以像函数那样调用 //仿函数是一个类&#xff0c;不是一个…

数据库操作php,一个数据库操作PHP类

/** Author 墨龙* Time 2010年12月2日 15:50:35*/$db new mysql($db_host,$db_user,$db_password,$db_table,$db_conn,$pre,$coding);class mysql{private $db_host;private $db_user;private $db_password;private $db_table;private $db_conn; //数据库连接标识;private $re…

STL18常用算法

#include<iostream> #include<algorithm> #include<vector> using namespace std; //transform 将一个容器中的元素搬运在另一个容器中 #if 0 //错误 struct PrintVector {void operator()(int v) {cout << v << " ";} }; void test0…