- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章SpringCloud Finchley Gateway 缓存请求Body和Form表单的实现由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
在接入spring-cloud-gateway时,可能有需求进行缓存json-body数据或者form-urlencoded数据的情况.
由于spring-cloud-gateway是以webflux为基础的响应式架构设计,所以在原有zuul基础上迁移过来的过程中,传统的编程思路,并不适合于reactor stream的开发.
网络上有许多缓存案例,但是在测试过程中出现各种bug问题,在缓存body时,需要考虑整体的响应式操作,才能更合理的缓存数据 。
下面提供缓存json-body数据或者form-urlencoded数据的具体实现方案,该方案经测试,满足各方面需求,以及避免了网络上其他缓存方案所出现的问题 。
定义一个gatewaycontext类,用于存储请求中缓存的数据 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
import
lombok.getter;
import
lombok.setter;
import
lombok.tostring;
import
org.springframework.util.linkedmultivaluemap;
import
org.springframework.util.multivaluemap;
@getter
@setter
@tostring
public
class
gatewaycontext {
public
static
final
string cache_gateway_context =
"cachegatewaycontext"
;
/**
* cache json body
*/
private
string cachebody;
/**
* cache formdata
*/
private
multivaluemap<string, string> formdata;
/**
* cache reqeust path
*/
private
string path;
}
|
实现globalfilter和ordered接口用于缓存请求数据 。
1 . 该示例只支持缓存下面3种mediatype 。
2 . 经验总结
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
|
import
com.choice.cloud.architect.usergate.option.filterorderenum;
import
com.choice.cloud.architect.usergate.support.gatewaycontext;
import
io.netty.buffer.bytebufallocator;
import
lombok.extern.slf4j.slf4j;
import
org.springframework.cloud.gateway.filter.gatewayfilterchain;
import
org.springframework.cloud.gateway.filter.globalfilter;
import
org.springframework.core.ordered;
import
org.springframework.core.io.bytearrayresource;
import
org.springframework.core.io.buffer.databuffer;
import
org.springframework.core.io.buffer.databufferutils;
import
org.springframework.core.io.buffer.nettydatabufferfactory;
import
org.springframework.http.httpheaders;
import
org.springframework.http.mediatype;
import
org.springframework.http.codec.httpmessagereader;
import
org.springframework.http.server.reactive.serverhttprequest;
import
org.springframework.http.server.reactive.serverhttprequestdecorator;
import
org.springframework.util.multivaluemap;
import
org.springframework.web.reactive.function.server.handlerstrategies;
import
org.springframework.web.reactive.function.server.serverrequest;
import
org.springframework.web.server.serverwebexchange;
import
reactor.core.publisher.flux;
import
reactor.core.publisher.mono;
import
java.io.unsupportedencodingexception;
import
java.net.urlencoder;
import
java.nio.charset.charset;
import
java.nio.charset.standardcharsets;
import
java.util.list;
import
java.util.map;
@slf4j
public
class
gatewaycontextfilter
implements
globalfilter, ordered {
/**
* default httpmessagereader
*/
private
static
final
list<httpmessagereader<?>> messagereaders = handlerstrategies.withdefaults().messagereaders();
@override
public
mono<
void
> filter(serverwebexchange exchange, gatewayfilterchain chain) {
/**
* save request path and serviceid into gateway context
*/
serverhttprequest request = exchange.getrequest();
string path = request.getpath().pathwithinapplication().value();
gatewaycontext gatewaycontext =
new
gatewaycontext();
gatewaycontext.getallrequestdata().addall(request.getqueryparams());
gatewaycontext.setpath(path);
/**
* save gateway context into exchange
*/
exchange.getattributes().put(gatewaycontext.cache_gateway_context,gatewaycontext);
httpheaders headers = request.getheaders();
mediatype contenttype = headers.getcontenttype();
long
contentlength = headers.getcontentlength();
if
(contentlength>
0
){
if
(mediatype.application_json.equals(contenttype) || mediatype.application_json_utf8.equals(contenttype)){
return
readbody(exchange, chain,gatewaycontext);
}
if
(mediatype.application_form_urlencoded.equals(contenttype)){
return
readformdata(exchange, chain,gatewaycontext);
}
}
log.debug(
"[gatewaycontext]contenttype:{},gateway context is set with {}"
,contenttype, gatewaycontext);
return
chain.filter(exchange);
}
@override
public
int
getorder() {
return
integer.min_value;
}
/**
* readformdata
* @param exchange
* @param chain
* @return
*/
private
mono<
void
> readformdata(serverwebexchange exchange,gatewayfilterchain chain,gatewaycontext gatewaycontext){
httpheaders headers = exchange.getrequest().getheaders();
return
exchange.getformdata()
.doonnext(multivaluemap -> {
gatewaycontext.setformdata(multivaluemap);
log.debug(
"[gatewaycontext]read formdata:{}"
,multivaluemap);
})
.then(mono.defer(() -> {
charset charset = headers.getcontenttype().getcharset();
charset = charset ==
null
? standardcharsets.utf_8:charset;
string charsetname = charset.name();
multivaluemap<string, string> formdata = gatewaycontext.getformdata();
/**
* formdata is empty just return
*/
if
(
null
== formdata || formdata.isempty()){
return
chain.filter(exchange);
}
stringbuilder formdatabodybuilder =
new
stringbuilder();
string entrykey;
list<string> entryvalue;
try
{
/**
* remove system param ,repackage form data
*/
for
(map.entry<string, list<string>> entry : formdata.entryset()) {
entrykey = entry.getkey();
entryvalue = entry.getvalue();
if
(entryvalue.size() >
1
) {
for
(string value : entryvalue){
formdatabodybuilder.append(entrykey).append(
"="
).append(urlencoder.encode(value, charsetname)).append(
"&"
);
}
}
else
{
formdatabodybuilder.append(entrykey).append(
"="
).append(urlencoder.encode(entryvalue.get(
0
), charsetname)).append(
"&"
);
}
}
}
catch
(unsupportedencodingexception e){
//ignore urlencode exception
}
/**
* substring with the last char '&'
*/
string formdatabodystring =
""
;
if
(formdatabodybuilder.length()>
0
){
formdatabodystring = formdatabodybuilder.substring(
0
, formdatabodybuilder.length() -
1
);
}
/**
* get data bytes
*/
byte
[] bodybytes = formdatabodystring.getbytes(charset);
int
contentlength = bodybytes.length;
serverhttprequestdecorator decorator =
new
serverhttprequestdecorator(
exchange.getrequest()) {
/**
* change content-length
* @return
*/
@override
public
httpheaders getheaders() {
httpheaders httpheaders =
new
httpheaders();
httpheaders.putall(
super
.getheaders());
if
(contentlength >
0
) {
httpheaders.setcontentlength(contentlength);
}
else
{
httpheaders.set(httpheaders.transfer_encoding,
"chunked"
);
}
return
httpheaders;
}
/**
* read bytes to flux<databuffer>
* @return
*/
@override
public
flux<databuffer> getbody() {
return
databufferutils.read(
new
bytearrayresource(bodybytes),
new
nettydatabufferfactory(bytebufallocator.
default
),contentlength);
}
};
serverwebexchange mutateexchange = exchange.mutate().request(decorator).build();
log.debug(
"[gatewaycontext]rewrite form data :{}"
,formdatabodystring);
return
chain.filter(mutateexchange);
}));
}
/**
* readjsonbody
* @param exchange
* @param chain
* @return
*/
private
mono<
void
> readbody(serverwebexchange exchange,gatewayfilterchain chain,gatewaycontext gatewaycontext){
/**
* join the body
*/
return
databufferutils.join(exchange.getrequest().getbody())
.flatmap(databuffer -> {
/**
* read the body flux<databuffer>
*/
databufferutils.retain(databuffer);
flux<databuffer> cachedflux = flux.defer(() -> flux.just(databuffer.slice(
0
, databuffer.readablebytecount())));
/**
* repackage serverhttprequest
*/
serverhttprequest mutatedrequest =
new
serverhttprequestdecorator(exchange.getrequest()) {
@override
public
flux<databuffer> getbody() {
return
cachedflux;
}
};
/**
* mutate exchage with new serverhttprequest
*/
serverwebexchange mutatedexchange = exchange.mutate().request(mutatedrequest).build();
/**
* read body string with default messagereaders
*/
return
serverrequest.create(mutatedexchange, messagereaders)
.bodytomono(string.
class
)
.doonnext(objectvalue -> {
gatewaycontext.setcachebody(objectvalue);
log.debug(
"[gatewaycontext]read jsonbody:{}"
,objectvalue);
}).then(chain.filter(mutatedexchange));
});
}
}
|
在后续filter中,可以直接从serverexchange中获取gatewaycontext,就可以获取到缓存的数据,如果需要缓存其他数据,则可以根据自己的需求,添加到gatewaycontext中即可 。
。
。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我.
原文链接:https://segmentfault.com/a/1190000017898354 。
最后此篇关于SpringCloud Finchley Gateway 缓存请求Body和Form表单的实现的文章就讲到这里了,如果你想了解更多关于SpringCloud Finchley Gateway 缓存请求Body和Form表单的实现的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
Spring Cloud Greenwich puts spring-cloud-netflix-zuul处于维护模式,所以我正在尝试从 Zuul 迁移到 Spring Cloud Gateway。
有没有办法对 AWS API Gateway 服务使用基本身份验证而不是 AWS4-HMAC-SHA256 身份验证?我需要支持仅支持使用基本身份验证的 webhook 调用的系统。 最佳答案 您只需
Rails API 通常喜欢这样的数组查询参数: example.com?colors[]=cyan&colors[]=magenta&colors[]=yellow&colors[]=black 我
Here蓝图中说,API 网关将响应 401: Unauthorized。 我写了同样的raise Exception('Unauthorized')在我的 lambda 中,并且能够从 Lambda
在 documentation我确实看到了如何使用 Hystrix 实现超时,但我只想确保没有实现默认超时。 最佳答案 现在还有一个 chapter关于文档中的一般超时。可以设置全局超时和每条路由超时
我的资源/api 有一个方法 POST,它将主体代理到 Kinesis Firehose(然后代理到 ES)。同时我希望它触发一个 Lambda 函数。 我尝试添加一个额外的方法 ANY 来触发 La
Spring Cloud Gateway 真的很新 - 但它“似乎”很容易。我真的很苦恼的一个问题。我的要求是为路径添加前缀,检查头变量,根据该变量查找 URI,然后继续前进。 问题是 uri 总是下
我已经使用 Websocket 协议(protocol)创建了一个 API 网关。部署 API 后,我得到一个 WebSocket URL 和一个连接 URL。 例如 WebSocket URL:ws
我正在使用 AWS API Gateway 和 AWS Lambda 创建一个无服务器的 REST API。虽然已创建端点并与相应的 Lambda 函数链接,但下一步是添加身份验证层以通过电子邮件和密
我们开发了一个应用程序,它提供多种休息服务,并支持 Accept-Encoding header ,以通过 Content-Encoding:gzip header 值返回压缩内容。 此应用程序部署在
我正在开发 CloudFormation 模板来部署 API Gateway 资源,但在部署 (AWS::ApiGateway::Deployment) 和UsagePlan 资源方面遇到问题。这有点
我目前正在使用 AWS API Gateway 开发 API。我正在向我的客户发布一个 JSON Web token (JWT)。该 JWT 使用 secret 进行签名。我目前将 secret 存储
我下载了 .NET SDK对于 Payflow Gateway 并遵循 these instructions关于设置我的 Payflow Gateway 测试帐户,然后修改两行 DOSecureTok
我目前正在将 Amazon CloudSearch 与前端应用程序集成。由于已知的 CORS 问题,我也被迫使用 API 网关。 出现的问题是,前端 CloudSearch 库发送带有编码参数的 ur
我正在创建一个 LambdaRestApi在 CDK 中,我想同时启用 CORS 并使用 addProxy 方法添加任何代理。 我目前有以下 CDK 代码: const api = new Lam
我们可以使用 AWS API Gateway 使用双向 SSL 功能吗?我们希望在我们的实时流应用程序中使用 API Gateway 作为 kinesis 的代理。 下面是我的要求 客户端向 apig
我正在构建一个无服务器 react 应用程序,它使用 Cognito 进行登录/注销。该应用程序调用 API 网关,该网关配置为使用 Cognito 用户池作为自定义授权方。 我还构建了一个 lamb
我已经浏览了 Google Cloud API Gateway docs并搜索 the public issue tracker但一直无法以某种方式提及它。 我最接近的是this google gro
我正在尝试将使用 spring-cloud-starter-netflix-zuul 的网关迁移到 Spring Cloud Gateway,但我遇到了请求路由问题。 我浏览了以下有关为 Discov
我正在尝试设置我的 API 网关,以便它具有以下简单的方法响应: 我正在使用 CloudFormation,但总是遇到错误。我相信这很简单,但在花了几个小时阅读文档后我陷入了困境。这是我的方法资源(在
我是一名优秀的程序员,十分优秀!