Spring Webflux 原始碼閱讀之 accept包
Spring Webflux --accept
RequestedContentTypeResolver策略和實現來解析給定請求的請求內容型別。
介面
RequestedContentTypeResolver
為ServerWebExchange解決請求的媒體型別的策略。
public interface RequestedContentTypeResolver {
/**
* Resolve the given request to a list of requested media types. The returned
* list is ordered by specificity first and by quality parameter second.
* @param exchange the current exchange
* @return the requested media types or an empty list
* @throws NotAcceptableStatusException if the requested media type is invalid
*/
List<MediaType> resolveMediaTypes(ServerWebExchange exchange);
}
將給定的請求解析為請求的媒體型別列表。返回的列表首先按特異性排序,然後按質量引數排序。
類
org.springframework.web.reactive.accept.FixedContentTypeResolver
解析器始終解析為媒體型別的固定列表。這可以用作“最後一行”策略,當客戶端沒有請求任何媒體型別時提供回撥
public class FixedContentTypeResolver implements RequestedContentTypeResolver {
private static final Log logger = LogFactory.getLog(FixedContentTypeResolver.class);
private final List<MediaType> mediaTypes;
/**
* 具有單個預設MediaType的建構函式。.
*/
public FixedContentTypeResolver(MediaType mediaType) {
this(Collections.singletonList(mediaType));
}
/**
* 使用預設的MediaType排序列表的建構函式返回用於支援各種內容型別的應用程式。
如果目標不存在,並且不支援任何其他預設媒體型別,請考慮在最後附加MediaType.ALL。
*/
public FixedContentTypeResolver(List<MediaType> mediaTypes) {
this.mediaTypes = Collections.unmodifiableList(mediaTypes);
}
/**
* 返回配置的媒體型別列表。
*/
public List<MediaType> getContentTypes() {
return this.mediaTypes;
}
@Override
public List<MediaType> resolveMediaTypes(ServerWebExchange exchange) {
if (logger.isDebugEnabled()) {
logger.debug("Requested media types: " + this.mediaTypes);
}
return this.mediaTypes;
}
}
org.springframework.web.reactive.accept.HeaderContentTypeResolver
解析器檢視請求的“Accept”標頭。
public class HeaderContentTypeResolver implements RequestedContentTypeResolver {
@Override
public List<MediaType> resolveMediaTypes(ServerWebExchange exchange) throws NotAcceptableStatusException {
try {
List<MediaType> mediaTypes = exchange.getRequest().getHeaders().getAccept();
MediaType.sortBySpecificityAndQuality(mediaTypes);
return mediaTypes;
}
catch (InvalidMediaTypeException ex) {
String value = exchange.getRequest().getHeaders().getFirst("Accept");
throw new NotAcceptableStatusException(
"Could not parse 'Accept' header [" + value + "]: " + ex.getMessage());
}
}
}
org.springframework.web.reactive.accept.ParameterContentTypeResolver
解析查詢引數並使用它查詢匹配的MediaType的解析器。查詢鍵可以註冊,也可以作為一個後備的MediaTypeFactory執行查詢。
public class ParameterContentTypeResolver implements RequestedContentTypeResolver {
/** Primary lookup for media types by key (e.g. "json" -> "application/json") */
private final Map<String, MediaType> mediaTypes = new ConcurrentHashMap<>(64);
private String parameterName = "format";
public ParameterContentTypeResolver(Map<String, MediaType> mediaTypes) {
mediaTypes.forEach((key, value) -> this.mediaTypes.put(formatKey(key), value));
}
private static String formatKey(String key) {
return key.toLowerCase(Locale.ENGLISH);
}
/**
* Set the name of the parameter to use to determine requested media types.
* <p>By default this is set to {@literal "format"}.
*/
public void setParameterName(String parameterName) {
Assert.notNull(parameterName, "'parameterName' is required");
this.parameterName = parameterName;
}
public String getParameterName() {
return this.parameterName;
}
@Override
public List<MediaType> resolveMediaTypes(ServerWebExchange exchange) throws NotAcceptableStatusException {
String key = exchange.getRequest().getQueryParams().getFirst(getParameterName());
if (!StringUtils.hasText(key)) {
return Collections.emptyList();
}
key = formatKey(key);
MediaType match = this.mediaTypes.get(key);
if (match == null) {
match = MediaTypeFactory.getMediaType("filename." + key)
.orElseThrow(() -> {
List<MediaType> supported = new ArrayList<>(this.mediaTypes.values());
return new NotAcceptableStatusException(supported);
});
}
this.mediaTypes.putIfAbsent(key, match);
return Collections.singletonList(match);
}
org.springframework.web.reactive.accept.RequestedContentTypeResolverBuilder
Builder的複合RequestedContentTypeResolver代表其他解析器實現一個不同的策略來確定請求的內容型別,例如Accept標頭,查詢引數,或其他。
使用生成器方法在所需的順序中新增解析器。對於給定的請求,他首先解析返回一個非空的列表,並且不包含只是MediaType。將使用。
預設情況下,如果沒有顯式解析器配置,構建器將新增HeaderContentTypeResolver。
public class RequestedContentTypeResolverBuilder {
private final List<Supplier<RequestedContentTypeResolver>> candidates = new ArrayList<>();
/**
* Add a resolver to get the requested content type from a query parameter.
* By default the query parameter name is {@code "format"}.
*/
public ParameterResolverConfigurer parameterResolver() {
ParameterResolverConfigurer parameterBuilder = new ParameterResolverConfigurer();
this.candidates.add(parameterBuilder::createResolver);
return parameterBuilder;
}
/**
* Add resolver to get the requested content type from the
* {@literal "Accept"} header.
*/
public void headerResolver() {
this.candidates.add(HeaderContentTypeResolver::new);
}
/**
* Add resolver that returns a fixed set of media types.
* @param mediaTypes the media types to use
*/
public void fixedResolver(MediaType... mediaTypes) {
this.candidates.add(() -> new FixedContentTypeResolver(Arrays.asList(mediaTypes)));
}
/**
* Add a custom resolver.
* @param resolver the resolver to add
*/
public void resolver(RequestedContentTypeResolver resolver) {
this.candidates.add(() -> resolver);
}
/**
* Build a {@link RequestedContentTypeResolver} that delegates to the list
* of resolvers configured through this builder.
*/
public RequestedContentTypeResolver build() {
List<RequestedContentTypeResolver> resolvers =
this.candidates.isEmpty() ?
Collections.singletonList(new HeaderContentTypeResolver()) :
this.candidates.stream().map(Supplier::get).collect(Collectors.toList());
return exchange -> {
for (RequestedContentTypeResolver resolver : resolvers) {
List<MediaType> type = resolver.resolveMediaTypes(exchange);
if (type.isEmpty() || (type.size() == 1 && type.contains(MediaType.ALL))) {
continue;
}
return type;
}
return Collections.emptyList();
};
}
/**
* Helper to create and configure {@link ParameterContentTypeResolver}.
*/
public static class ParameterResolverConfigurer {
private final Map<String, MediaType> mediaTypes = new HashMap<>();
@Nullable
private String parameterName;
/**
* Configure a mapping between a lookup key (extracted from a query
* parameter value) and a corresponding {@code MediaType}.
* @param key the lookup key
* @param mediaType the MediaType for that key
*/
public ParameterResolverConfigurer mediaType(String key, MediaType mediaType) {
this.mediaTypes.put(key, mediaType);
return this;
}
/**
* Map-based variant of {@link #mediaType(String, MediaType)}.
* @param mediaTypes the mappings to copy
*/
public ParameterResolverConfigurer mediaType(Map<String, MediaType> mediaTypes) {
this.mediaTypes.putAll(mediaTypes);
return this;
}
/**
* Set the name of the parameter to use to determine requested media types.
* <p>By default this is set to {@literal "format"}.
*/
public ParameterResolverConfigurer parameterName(String parameterName) {
this.parameterName = parameterName;
return this;
}
/**
* Private factory method to create the resolver.
*/
private RequestedContentTypeResolver createResolver() {
ParameterContentTypeResolver resolver = new ParameterContentTypeResolver(this.mediaTypes);
if (this.parameterName != null) {
resolver.setParameterName(this.parameterName);
}
return resolver;
}
}
}
相關文章
- buffer 原始碼包閱讀原始碼
- Spring 原始碼閱讀之標籤解析Spring原始碼
- 【初學】Spring原始碼筆記之零:閱讀原始碼Spring原始碼筆記
- 【原始碼閱讀】Glide原始碼閱讀之with方法(一)原始碼IDE
- 【原始碼閱讀】Glide原始碼閱讀之into方法(三)原始碼IDE
- spring原始碼閱讀環境(幾分鐘下載包)Spring原始碼
- 【原始碼閱讀】AndPermission原始碼閱讀原始碼
- 【原始碼閱讀】Glide原始碼閱讀之load方法(二)原始碼IDE
- 第 31 期 flag 包原始碼閱讀原始碼
- Spring原始碼閱讀-IoC容器解析Spring原始碼
- Spring原始碼閱讀學習一Spring原始碼
- Spring原始碼閱讀——ClassPathXmlApplicationContext(二)Spring原始碼XMLAPPContext
- spring原始碼閱讀筆記08:bean載入之建立beanSpring原始碼筆記Bean
- Python原始碼閱讀-閉包的實現Python原始碼
- Flume-NG原始碼閱讀之FileChannel原始碼
- Flume-NG原始碼閱讀之AvroSink原始碼VRROS
- spring原始碼閱讀--容器啟動過程Spring原始碼
- Spring 6 原始碼編譯和高效閱讀原始碼技巧分享Spring原始碼編譯
- ReactorKit原始碼閱讀React原始碼
- AQS原始碼閱讀AQS原始碼
- CountDownLatch原始碼閱讀CountDownLatch原始碼
- HashMap 原始碼閱讀HashMap原始碼
- delta原始碼閱讀原始碼
- 原始碼閱讀-HashMap原始碼HashMap
- NGINX原始碼閱讀Nginx原始碼
- Mux 原始碼閱讀UX原始碼
- HashMap原始碼閱讀HashMap原始碼
- fuzz原始碼閱讀原始碼
- RunLoop 原始碼閱讀OOP原始碼
- express 原始碼閱讀Express原始碼
- muduo原始碼閱讀原始碼
- stack原始碼閱讀原始碼
- Spring WebFlux安全配置教程和原始碼 - vinsguruSpringWebUX原始碼
- 原始碼閱讀之ArrayList實現細節原始碼
- 原始碼閱讀之Java棧的實現原始碼Java
- PostgreSQL 原始碼解讀(3)- 如何閱讀原始碼SQL原始碼
- JDK原始碼閱讀:Object類閱讀筆記JDK原始碼Object筆記
- Laravel 原始碼閱讀 - QueueLaravel原始碼