下面列出了怎么用org.springframework.http.server.reactive.ServerHttpRequest的API类实例代码及写法,或者点击链接到github查看源代码。
@GetMapping(MONO_ENDPOINT_PATH)
@ResponseBody
Mono<String> monoEndpoint(ServerHttpRequest request) {
HttpHeaders headers = request.getHeaders();
if ("true".equals(headers.getFirst("throw-exception"))) {
throw new ApiException(ERROR_THROWN_IN_MONO_ENDPOINT);
}
if ("true".equals(headers.getFirst("return-exception-in-mono"))) {
return Mono.error(
new ApiException(ERROR_RETURNED_IN_MONO_ENDPOINT_MONO)
);
}
return Mono.just(MONO_RESPONSE_PAYLOAD);
}
@Override
protected Mono<Void> writeToInternal(ServerWebExchange exchange, Context context) {
return this.inserter.insert(exchange.getResponse(), new BodyInserter.Context() {
@Override
public List<HttpMessageWriter<?>> messageWriters() {
return context.messageWriters();
}
@Override
public Optional<ServerHttpRequest> serverRequest() {
return Optional.of(exchange.getRequest());
}
@Override
public Map<String, Object> hints() {
hints.put(Hints.LOG_PREFIX_HINT, exchange.getLogPrefix());
return hints;
}
});
}
/**
* 从request中获取token
*
* @param request request
* @return token
*/
private String getTokenFromRequest(ServerHttpRequest request) {
List<String> headers = request.getHeaders()
.get(ConstantsSecurity.AUTHORIZATION_HEADER);
if (CollectionUtils.isEmpty(headers)) {
throw new LightSecurityException("没有找到名为Authorization的header");
}
String header = headers.get(0);
if (!header.startsWith(ConstantsSecurity.BEARER)) {
throw new LightSecurityException("token必须以'Bearer '开头");
}
if (header.length() <= SEVEN) {
throw new LightSecurityException("token非法,长度 <= 7");
}
return header.substring(SEVEN);
}
/**
* Check if the request is a same-origin one, based on {@code Origin}, and
* {@code Host} headers.
*
* <p><strong>Note:</strong> as of 5.1 this method ignores
* {@code "Forwarded"} and {@code "X-Forwarded-*"} headers that specify the
* client-originated address. Consider using the {@code ForwardedHeaderFilter}
* to extract and use, or to discard such headers.
*
* @return {@code true} if the request is a same-origin one, {@code false} in case
* of a cross-origin request
* @deprecated as of 5.2, same-origin checks are performed directly by {@link #isCorsRequest}
*/
@Deprecated
public static boolean isSameOrigin(ServerHttpRequest request) {
String origin = request.getHeaders().getOrigin();
if (origin == null) {
return true;
}
URI uri = request.getURI();
String actualScheme = uri.getScheme();
String actualHost = uri.getHost();
int actualPort = getPort(uri.getScheme(), uri.getPort());
Assert.notNull(actualScheme, "Actual request scheme must not be null");
Assert.notNull(actualHost, "Actual request host must not be null");
Assert.isTrue(actualPort != -1, "Actual request port must not be undefined");
UriComponents originUrl = UriComponentsBuilder.fromOriginHeader(origin).build();
return (actualScheme.equals(originUrl.getScheme()) &&
actualHost.equals(originUrl.getHost()) &&
actualPort == getPort(originUrl.getScheme(), originUrl.getPort()));
}
@Override
public Mono<Void> filter(ServerWebExchange serverWebExchange, GatewayFilterChain chain) {
ServerHttpRequest request = serverWebExchange.getRequest();
ServerHttpResponse response = serverWebExchange.getResponse();
HttpHeaders headers = response.getHeaders();
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, "*");
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, "POST, GET, PUT, OPTIONS, DELETE, PATCH");
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, "*");
headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, ALL);
headers.add(HttpHeaders.ACCESS_CONTROL_MAX_AGE, MAX_AGE);
if (request.getMethod() == HttpMethod.OPTIONS) {
response.setStatusCode(HttpStatus.OK);
return Mono.empty();
}
return chain.filter(serverWebExchange);
}
@SuppressWarnings("deprecation")
private void testWithForwardedHeader(String serverName, int port,
String forwardedHeader, String originHeader) {
String url = "http://" + serverName;
if (port != -1) {
url = url + ":" + port;
}
MockServerHttpRequest.BaseBuilder<?> builder = get(url)
.header("Forwarded", forwardedHeader)
.header(HttpHeaders.ORIGIN, originHeader);
ServerHttpRequest request = adaptFromForwardedHeaders(builder);
assertTrue(CorsUtils.isSameOrigin(request));
}
@Override
protected Mono<Void> writeToInternal(ServerWebExchange exchange, Context context) {
return this.inserter.insert(exchange.getResponse(), new BodyInserter.Context() {
@Override
public List<HttpMessageWriter<?>> messageWriters() {
return context.messageWriters();
}
@Override
public Optional<ServerHttpRequest> serverRequest() {
return Optional.of(exchange.getRequest());
}
@Override
public Map<String, Object> hints() {
hints.put(Hints.LOG_PREFIX_HINT, exchange.getLogPrefix());
return hints;
}
});
}
/**
* It checks whether a request should be traced or not.
*
* @return whether request should be traced or not
*/
protected boolean shouldBeTraced(final ServerHttpRequest request) {
final PathContainer pathWithinApplication = request.getPath().pathWithinApplication();
// skip URLs matching skip pattern
// e.g. pattern is defined as '/health|/status' then URL 'http://localhost:5000/context/health' won't be traced
if (skipPattern != null) {
final String url = pathWithinApplication.value();
if (skipPattern.matcher(url).matches()) {
if (LOG.isTraceEnabled()) {
LOG.trace("Not tracing request " + request + " because it matches skip pattern: " + skipPattern);
}
return false;
}
}
if (!urlPatterns.isEmpty() && urlPatterns.stream().noneMatch(urlPattern -> urlPattern.matches(pathWithinApplication))) {
if (LOG.isTraceEnabled()) {
LOG.trace("Not tracing request " + request + " because it does not match any URL pattern: " + urlPatterns);
}
return false;
}
return true;
}
@Override
public Mono<Void> filter(final ServerWebExchange exchange, final WebFilterChain chain) {
final ServerHttpRequest request = exchange.getRequest();
if (!shouldBeTraced(request)) {
return chain.filter(exchange);
}
if (exchange.getAttribute(SERVER_SPAN_CONTEXT) != null) {
if (LOG.isTraceEnabled()) {
LOG.trace("Not tracing request " + request + " because it is already being traced");
}
return chain.filter(exchange);
}
return new TracingOperator(chain.filter(exchange), exchange, tracer, spanDecorators);
}
@GetMapping(FLUX_ENDPOINT_PATH)
@ResponseBody
Flux<String> fluxEndpoint(ServerHttpRequest request) {
HttpHeaders headers = request.getHeaders();
if ("true".equals(headers.getFirst("throw-exception"))) {
sleepThread(SLEEP_TIME_MILLIS);
throw new RuntimeException("Error thrown in fluxEndpoint(), outside Flux");
}
if ("true".equals(headers.getFirst("return-exception-in-flux"))) {
return Flux.just("foo")
.delayElements(Duration.ofMillis(SLEEP_TIME_MILLIS))
.map(d -> {
throw new RuntimeException("Error thrown in fluxEndpoint(), inside Flux");
});
}
long delayPerElementMillis = SLEEP_TIME_MILLIS / FLUX_ENDPOINT_PAYLOAD.size();
return Flux.fromIterable(FLUX_ENDPOINT_PAYLOAD).delayElements(Duration.ofMillis(delayPerElementMillis));
}
@RequestMapping(path = REQUEST_MAPPING_PATH, method = {RequestMethod.GET, RequestMethod.HEAD, RequestMethod.POST, RequestMethod.PUT, RequestMethod.PATCH, RequestMethod.DELETE, RequestMethod.OPTIONS})
public Mono<Void> endpointProxy(@PathVariable("instanceId") String instanceId,
ServerHttpRequest request,
ServerHttpResponse response) {
String endpointLocalPath = getEndpointLocalPath(request.getPath().pathWithinApplication().value());
URI uri = UriComponentsBuilder.fromPath(endpointLocalPath)
.query(request.getURI().getRawQuery())
.build(true)
.toUri();
return super.forward(instanceId, uri, request.getMethod(), request.getHeaders(),
() -> BodyInserters.fromDataBuffers(request.getBody())).flatMap(clientResponse -> {
response.setStatusCode(clientResponse.statusCode());
response.getHeaders().addAll(filterHeaders(clientResponse.headers().asHttpHeaders()));
return response.writeAndFlushWith(clientResponse.body(BodyExtractors.toDataBuffers()).window(1));
});
}
@Test
public void resolveParts() {
ServerHttpRequest request = generateMultipartRequest();
ResolvableType elementType = forClassWithGenerics(MultiValueMap.class, String.class, Part.class);
MultiValueMap<String, Part> parts = this.reader.readMono(elementType, request, emptyMap()).block();
assertEquals(2, parts.size());
assertTrue(parts.containsKey("fooPart"));
Part part = parts.getFirst("fooPart");
assertTrue(part instanceof FilePart);
assertEquals("fooPart", part.name());
assertEquals("foo.txt", ((FilePart) part).filename());
DataBuffer buffer = DataBufferUtils.join(part.content()).block();
assertEquals(12, buffer.readableByteCount());
byte[] byteContent = new byte[12];
buffer.read(byteContent);
assertEquals("Lorem Ipsum.", new String(byteContent));
assertTrue(parts.containsKey("barPart"));
part = parts.getFirst("barPart");
assertTrue(part instanceof FormFieldPart);
assertEquals("barPart", part.name());
assertEquals("bar", ((FormFieldPart) part).value());
}
@Override
@SuppressWarnings("all")
public Mono<Void> filter(final ServerWebExchange exchange, final WebFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
if (CorsUtils.isCorsRequest(request)) {
ServerHttpResponse response = exchange.getResponse();
HttpHeaders headers = response.getHeaders();
headers.add("Access-Control-Allow-Origin", ALLOWED_ORIGIN);
headers.add("Access-Control-Allow-Methods", ALLOWED_METHODS);
headers.add("Access-Control-Max-Age", MAX_AGE);
headers.add("Access-Control-Allow-Headers", ALLOWED_HEADERS);
headers.add("Access-Control-Expose-Headers", ALLOWED_EXPOSE);
headers.add("Access-Control-Allow-Credentials", "true");
if (request.getMethod() == HttpMethod.OPTIONS) {
response.setStatusCode(HttpStatus.OK);
return Mono.empty();
}
}
return chain.filter(exchange);
}
@Override
public GatewayFilter apply(Object config) {
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
// 不是登录请求,直接向下执行
if (!StrUtil.containsAnyIgnoreCase(request.getURI().getPath(), SecurityConstants.OAUTH_TOKEN_URL)) {
return chain.filter(exchange);
}
URI uri = exchange.getRequest().getURI();
String queryParam = uri.getRawQuery();
Map<String, String> paramMap = HttpUtil.decodeParamMap(queryParam, CharsetUtil.UTF_8);
String password = paramMap.get(PASSWORD);
if (StrUtil.isNotBlank(password)) {
try {
password = decryptAES(password, encodeKey);
} catch (Exception e) {
log.error("密码解密失败:{}", password);
return Mono.error(e);
}
paramMap.put(PASSWORD, password.trim());
}
URI newUri = UriComponentsBuilder.fromUri(uri)
.replaceQuery(HttpUtil.toParams(paramMap))
.build(true)
.toUri();
ServerHttpRequest newRequest = exchange.getRequest().mutate().uri(newUri).build();
return chain.filter(exchange.mutate().request(newRequest).build());
};
}
private void addHeader(ServerHttpRequest.Builder mutate, String name, Object value) {
if (ObjectUtil.isEmpty(value)) {
return;
}
String valueStr = value.toString();
String valueEncode = URLUtil.encode(valueStr);
mutate.header(name, valueEncode);
}
@Test // SPR-17525
public void shouldNotDoubleEncode() throws Exception {
HttpHeaders headers = new HttpHeaders();
headers.add("Forwarded", "host=84.198.58.199;proto=https");
ServerHttpRequest request = MockServerHttpRequest
.method(HttpMethod.GET, new URI("https://example.com/a%20b?q=a%2Bb"))
.headers(headers)
.build();
request = this.requestMutator.apply(request);
assertEquals(new URI("https://84.198.58.199/a%20b?q=a%2Bb"), request.getURI());
assertForwardedHeadersRemoved(request);
}
private HttpErrorInfo createHttpErrorInfo(HttpStatus httpStatus, ServerHttpRequest request, Exception ex) {
final String path = request.getPath().pathWithinApplication().value();
final String message = ex.getMessage();
LOG.debug("Returning HTTP status: {} for path: {}, message: {}", httpStatus, path, message);
return new HttpErrorInfo(httpStatus, path, message);
}
public ServerHttpRequest doFilter(ServerHttpRequest request) {
ServerHttpRequest req = request;
String authorization = request.getHeaders().getFirst("Authorization");
String requestURI = request.getURI().getPath();
// test if request url is permit all , then remove authorization from header
LOGGER.info(String.format("Enhance request URI : %s.", requestURI));
if (StringUtils.isNotEmpty(authorization)) {
if (isJwtBearerToken(authorization)) {
try {
authorization = StringUtils.substringBetween(authorization, ".");
String decoded = new String(Base64.decodeBase64(authorization));
Map properties = new ObjectMapper().readValue(decoded, Map.class);
String userId = (String) properties.get(USER_ID_IN_HEADER);
req = request.mutate()
.header(USER_ID_IN_HEADER, userId)
.build();
} catch (Exception e) {
LOGGER.error("Failed to customize header for the request, but still release it as the it would be regarded without any user details.", e);
}
}
} else {
LOGGER.info("Regard this request as anonymous request, so set anonymous user_id in the header.");
req = request.mutate()
.header(USER_ID_IN_HEADER, ANONYMOUS_USER_ID)
.build();
}
return req;
}
@SuppressWarnings("unchecked")
private void mockUrlParams(/*@Mock*/ ServerHttpRequest request, Map<String, String> paramMap) {
MultiValueMap<String, String> urlParams = mock(MultiValueMap.class);
when(request.getQueryParams()).thenReturn(urlParams);
for (Map.Entry<String, String> e : paramMap.entrySet()) {
when(urlParams.getFirst(e.getKey())).thenReturn(e.getValue());
}
}
/**
* 请求信息日志过滤器
*
* @param exchange ServerWebExchange
* @param chain GatewayFilterChain
* @return Mono
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
HttpHeaders headers = request.getHeaders();
HttpMethod method = request.getMethod();
RequestPath path = request.getPath();
String source = getIp(headers);
if (source == null || source.isEmpty()) {
source = request.getRemoteAddress().getAddress().getHostAddress();
}
String requestId = Util.uuid();
String fingerprint = Util.md5(source + headers.getFirst("user-agent"));
LogDto log = new LogDto();
log.setRequestId(requestId);
log.setSource(source);
log.setMethod(method.name());
log.setUrl(path.value());
log.setHeaders(headers.toSingleValueMap());
request.mutate().header("requestId", requestId).build();
request.mutate().header("fingerprint", fingerprint).build();
// 读取请求参数
MultiValueMap<String, String> params = request.getQueryParams();
log.setParams(params.isEmpty() ? null : params.toSingleValueMap());
// 如请求方法为GET或Body为空或Body不是Json,则打印日志后结束
long length = headers.getContentLength();
MediaType contentType = headers.getContentType();
if (length <= 0 || !contentType.equalsTypeAndSubtype(MediaType.APPLICATION_JSON)) {
logger.info("请求参数: {}", log.toString());
return chain.filter(exchange);
}
return readBody(exchange, chain, log);
}
@Nullable
private static String getForwardedPrefix(ServerHttpRequest request) {
HttpHeaders headers = request.getHeaders();
String prefix = headers.getFirst("X-Forwarded-Prefix");
if (prefix != null) {
int endIndex = prefix.length();
while (endIndex > 1 && prefix.charAt(endIndex - 1) == '/') {
endIndex--;
}
prefix = (endIndex != prefix.length() ? prefix.substring(0, endIndex) : prefix);
}
return prefix;
}
private void mockClientHostAddress(/*@Mock*/ ServerHttpRequest request, String address) {
InetSocketAddress socketAddress = mock(InetSocketAddress.class);
when(request.getRemoteAddress()).thenReturn(socketAddress);
InetAddress inetAddress = mock(InetAddress.class);
when(inetAddress.getHostAddress()).thenReturn(address);
when(socketAddress.getAddress()).thenReturn(inetAddress);
}
@Test // SPR-17525
public void shouldNotDoubleEncode() throws Exception {
HttpHeaders headers = new HttpHeaders();
headers.add("Forwarded", "host=84.198.58.199;proto=https");
ServerHttpRequest request = MockServerHttpRequest
.method(HttpMethod.GET, new URI("http://example.com/a%20b?q=a%2Bb"))
.headers(headers)
.build();
request = this.requestMutator.apply(request);
assertEquals(new URI("https://84.198.58.199/a%20b?q=a%2Bb"), request.getURI());
assertForwardedHeadersRemoved(request);
}
@Test
public void xForwardedPrefixTrailingSlash() throws Exception {
HttpHeaders headers = new HttpHeaders();
headers.add("X-Forwarded-Prefix", "/prefix////");
ServerHttpRequest request = this.requestMutator.apply(getRequest(headers));
assertEquals(new URI("http://example.com/prefix/path"), request.getURI());
assertEquals("/prefix/path", request.getPath().value());
assertForwardedHeadersRemoved(request);
}
@Override
public Mono<Void> filter(ServerWebExchange serverWebExchange, WebFilterChain webFilterChain) {
ServerHttpRequest request = serverWebExchange.getRequest();
if (request.getURI()
.getPath()
.equals("/")) {
return webFilterChain.filter(serverWebExchange.mutate()
.request(builder -> builder.method(request.getMethod())
.contextPath(request.getPath()
.toString())
.path("/test"))
.build());
}
return webFilterChain.filter(serverWebExchange);
}
@Override
public void onRequest(final ServerWebExchange exchange, final Span span) {
final ServerHttpRequest request = exchange.getRequest();
final HttpHeaders headers = request.getHeaders();
Optional.ofNullable(headers.getFirst("Prefer"))
.ifPresent(prefer -> span.setTag(PREFER, prefer));
}
@Override
public Mono<Void> writeTo(ClientHttpRequest request, ExchangeStrategies strategies) {
HttpHeaders requestHeaders = request.getHeaders();
if (!this.headers.isEmpty()) {
this.headers.entrySet().stream()
.filter(entry -> !requestHeaders.containsKey(entry.getKey()))
.forEach(entry -> requestHeaders
.put(entry.getKey(), entry.getValue()));
}
MultiValueMap<String, HttpCookie> requestCookies = request.getCookies();
if (!this.cookies.isEmpty()) {
this.cookies.forEach((name, values) -> values.forEach(value -> {
HttpCookie cookie = new HttpCookie(name, value);
requestCookies.add(name, cookie);
}));
}
return this.body.insert(request, new BodyInserter.Context() {
@Override
public List<HttpMessageWriter<?>> messageWriters() {
return strategies.messageWriters();
}
@Override
public Optional<ServerHttpRequest> serverRequest() {
return Optional.empty();
}
@Override
public Map<String, Object> hints() {
return Hints.from(Hints.LOG_PREFIX_HINT, logPrefix());
}
});
}
@Bean
public WebFilter corsFilter() {
return (ServerWebExchange ctx, WebFilterChain chain) -> {
ServerHttpRequest request = ctx.getRequest();
if (CorsUtils.isCorsRequest(request)) {
HttpHeaders requestHeaders = request.getHeaders();
ServerHttpResponse response = ctx.getResponse();
HttpMethod requestMethod = requestHeaders.getAccessControlRequestMethod();
HttpHeaders headers = response.getHeaders();
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, requestHeaders.getOrigin());
headers.addAll(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS,
requestHeaders.getAccessControlRequestHeaders());
if (requestMethod != null) {
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, requestMethod.name());
}
headers.add(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
headers.add(HttpHeaders.ACCESS_CONTROL_EXPOSE_HEADERS, "*");
headers.add(HttpHeaders.ACCESS_CONTROL_MAX_AGE, MAX_AGE);
if (request.getMethod() == HttpMethod.OPTIONS) {
response.setStatusCode(HttpStatus.OK);
return Mono.empty();
}
}
return chain.filter(ctx);
};
}
private HandshakeInfo createHandshakeInfo(ServerWebExchange exchange, ServerHttpRequest request,
@Nullable String protocol, Map<String, Object> attributes) {
URI uri = request.getURI();
// Copy request headers, as they might be pooled and recycled by
// the server implementation once the handshake HTTP exchange is done.
HttpHeaders headers = new HttpHeaders();
headers.addAll(request.getHeaders());
Mono<Principal> principal = exchange.getPrincipal();
String logPrefix = exchange.getLogPrefix();
InetSocketAddress remoteAddress = request.getRemoteAddress();
return new HandshakeInfo(uri, headers, principal, protocol, remoteAddress, attributes, logPrefix);
}
@GetMapping(path = RESPONSE_STATUS_EX_FOR_SPECIFIC_STATUS_CODE_ENDPOINT)
@ResponseBody
public String responseStatusExForSpecificStatusCodeEndpoint(ServerHttpRequest request) {
int desiredStatusCode = Integer.parseInt(
request.getHeaders().getFirst("desired-status-code")
);
throw new ResponseStatusException(
HttpStatus.resolve(desiredStatusCode),
"Synthetic ResponseStatusException with specific desired status code: " + desiredStatusCode
);
}