/* * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */
@Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain){ // the cached ServerHttpRequest is used when the ServerWebExchange can not be // mutated, for example, during a predicate where the body is read, but still // needs to be cached. // 如果谓词 ServerHttpRequest cachedRequest = exchange .getAttributeOrDefault(CACHED_SERVER_HTTP_REQUEST_DECORATOR_ATTR, null); // 如果读取body的谓词工厂(ReadBodyPredicateFactory)已经缓存过了请求body, // 说明 ServerWebExchange.CACHED_REQUEST_BODY_ATTR之前也已经缓存过,并且把CACHED_SERVER_HTTP_REQUEST_DECORATOR_ATTR缓存清空 if (cachedRequest != null) { exchange.getAttributes().remove(CACHED_SERVER_HTTP_REQUEST_DECORATOR_ATTR); return chain.filter(exchange.mutate().request(cachedRequest).build()); }
// DataBuffer body = exchange.getAttributeOrDefault(CACHED_REQUEST_BODY_ATTR, null); Route route = exchange.getAttribute(GATEWAY_ROUTE_ATTR); // 缓存的body不为空 说明之前缓存过 if (body != null || !this.routesToCache.containsKey(route.getId())) { return chain.filter(exchange); } // 此处是缓存过滤器的核心,在此工具方法中会将缓存存入网关上下文之中 // 将请求正文缓存在ServerWebExchange属性中。 // 该属性为{@link CACHED_REQUEST_BODY_ATTR}。 // 如果从无法变更ServerWebExchange的位置(例如谓词)调用此方法,则将cacheDecoratedRequest设置为true会将{@link ServerHttpRequestDecorator}放在属性{@link CACHED_SERVER_HTTP_REQUEST_DECORATOR_ATTR}中,以备后用。 return ServerWebExchangeUtils.cacheRequestBody(exchange, (serverHttpRequest) -> { // don't mutate and build if same request object if (serverHttpRequest == exchange.getRequest()) { return chain.filter(exchange); } return chain.filter(exchange.mutate().request(serverHttpRequest).build()); }); }
/* * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */
/* * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */
// TODO: use framework if possible // TODO: port to WebClientWriteResponseFilter privatebooleanisStreamingMediaType(@Nullable MediaType contentType){ // 判断给定的Media类型 是否与响应头contentType兼容 return (contentType != null && this.streamingMediaTypes.stream() .anyMatch(contentType::isCompatibleWith)); }
/* * Copyright 2013-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */
RequestBodySpec bodySpec = this.webClient.method(method).uri(requestUrl) .headers(httpHeaders -> { httpHeaders.addAll(filteredHeaders); // TODO: can this support preserviceHostHeader? if (!preserveHost) { httpHeaders.remove(HttpHeaders.HOST); } });
return headersSpec.exchange() // .log("webClient route") .flatMap(res -> { ServerHttpResponse response = exchange.getResponse(); response.getHeaders().putAll(res.headers().asHttpHeaders()); response.setStatusCode(res.statusCode()); // Defer committing the response until all route filters have run // Put client response as ServerWebExchange attribute and write // response later NettyWriteResponseFilter exchange.getAttributes().put(CLIENT_RESPONSE_ATTR, res); return chain.filter(exchange); }); }
privatebooleanrequiresBody(HttpMethod method){ switch (method) { case PUT: case POST: case PATCH: returntrue; default: returnfalse; } }