在Spring Cloud中,有时候需要对前端直接调用的微服务,进行请求内容重组,这时候可以通过自定义org.springframework.cloud.gateway.filter.GlobalFilter,org.springframework.cloud.gateway.filter.factory.rewrite.RewriteFunction,来满足需求。
下面的例子,是前端通过Gateway调用后端的文件服务,获取上传OSS的一些必要信息。通过重组,可以简化和规范使用。
自定义RewriteFunction
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import org.apache.commons.lang3.StringUtils;
import org.reactivestreams.Publisher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.cloud.gateway.filter.factory.rewrite.RewriteFunction;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import reactor.core.publisher.Mono;
@Component
public class FileServiceRequestRewriteFunction implements RewriteFunction<byte[], byte[]> {
private static final Logger logger = LoggerFactory.getLogger(FileServiceRequestRewriteFunction.class);
private Environment environment;
private ObjectMapper objectMapper;
private FileServiceProperties fileServiceProperties;
public FileServiceRequestRewriteFunction(Environment environment, ObjectMapper objectMapper,
FileServiceProperties fileServiceProperties) {
this.environment = environment;
this.objectMapper = objectMapper;
this.fileServiceProperties = fileServiceProperties;
}
@Override
public Publisher<byte[]> apply(ServerWebExchange t, byte[] u) {
UploadTokenRequest uploadTokenRequest = new UploadTokenRequest();
try {
uploadTokenRequest = objectMapper.readValue(u, UploadTokenRequest.class);
} catch (IOException e) {
logger.error("转换异常", e);
return Mono.just(u);
}
var ossUploadFile = new OssUploadFile();
BeanUtils.copyProperties(uploadTokenRequest, ossUploadFile);
ossUploadFile.bucket = fileServiceProperties.getTypeBuckets().getOrDefault(uploadTokenRequest.getType(),
fileServiceProperties.getDefaultBucket());
ossUploadFile.prefix = getPrefix(uploadTokenRequest.getType(), uploadTokenRequest.getPrefix());
try {
return Mono.just(objectMapper.writeValueAsBytes(ossUploadFile));
} catch (JsonProcessingException e) {
logger.error("转换异常", e);
return Mono.just(u);
}
}
private String getActiveProfile() {
var profiles = environment.getActiveProfiles();
return profiles.length > 0 ? profiles[0] : "";
}
private String getPrefix(String type, String prefix) {
var activeProfile = getActiveProfile();
var sb = new StringBuilder();
if (StringUtils.isNotBlank(activeProfile) && !activeProfile.equalsIgnoreCase("prod")) {
sb.append(activeProfile.toLowerCase());
}
if (StringUtils.isNotBlank(type)) {
if (!sb.isEmpty()) {
sb.append("/");
}
sb.append(type.toLowerCase());
}
if (StringUtils.isNotBlank(prefix)) {
if (!sb.isEmpty()) {
sb.append("/");
}
sb.append(prefix);
} else {
if (!sb.isEmpty()) {
sb.append("/");
}
sb.append(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")));
}
return sb.toString();
}
static class UploadTokenRequest {
private String type;
private String bucket;
private String prefix;
private String fileKey;
private String sourceFile;
private Long sourceFileSize;
private String sourceFileType;
private Integer useSourceFilename;
private Long expiredInSec;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getBucket() {
return bucket;
}
public void setBucket(String bucket) {
this.bucket = bucket;
}
public String getPrefix() {
return prefix;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
public String getFileKey() {
return fileKey;
}
public void setFileKey(String fileKey) {
this.fileKey = fileKey;
}
public String getSourceFile() {
return sourceFile;
}
public void setSourceFile(String sourceFile) {
this.sourceFile = sourceFile;
}
public Long getSourceFileSize() {
return sourceFileSize;
}
public void setSourceFileSize(Long sourceFileSize) {
this.sourceFileSize = sourceFileSize;
}
public String getSourceFileType() {
return sourceFileType;
}
public void setSourceFileType(String sourceFileType) {
this.sourceFileType = sourceFileType;
}
public Integer getUseSourceFilename() {
return useSourceFilename;
}
public void setUseSourceFilename(Integer useSourceFilename) {
this.useSourceFilename = useSourceFilename;
}
public Long getExpiredInSec() {
return expiredInSec;
}
public void setExpiredInSec(Long expiredInSec) {
this.expiredInSec = expiredInSec;
}
}
static class OssUploadFile {
private String bucket;
private String prefix;
private String fileKey;
private String sourceFile;
private Long sourceFileSize;
private String sourceFileType;
private Integer useSourceFilename;
private Long expiredInSec;
public String getBucket() {
return bucket;
}
public void setBucket(String bucket) {
this.bucket = bucket;
}
public String getPrefix() {
return prefix;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
public String getFileKey() {
return fileKey;
}
public void setFileKey(String fileKey) {
this.fileKey = fileKey;
}
public String getSourceFile() {
return sourceFile;
}
public void setSourceFile(String sourceFile) {
this.sourceFile = sourceFile;
}
public Long getSourceFileSize() {
return sourceFileSize;
}
public void setSourceFileSize(Long sourceFileSize) {
this.sourceFileSize = sourceFileSize;
}
public String getSourceFileType() {
return sourceFileType;
}
public void setSourceFileType(String sourceFileType) {
this.sourceFileType = sourceFileType;
}
public Integer getUseSourceFilename() {
return useSourceFilename;
}
public void setUseSourceFilename(Integer useSourceFilename) {
this.useSourceFilename = useSourceFilename;
}
public Long getExpiredInSec() {
return expiredInSec;
}
public void setExpiredInSec(Long expiredInSec) {
this.expiredInSec = expiredInSec;
}
}
}
自定义GlobalFilter
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.factory.rewrite.ModifyRequestBodyGatewayFilterFactory;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
/**
* 文件服务全局过滤器
*/
@Component
public class FileServiceGatewayGlobalFilter implements GlobalFilter {
private ModifyRequestBodyGatewayFilterFactory modifyRequestBodyGatewayFilterFactory;
private FileServiceProperties fileServiceProperties;
private FileServiceRequestRewriteFunction fileServiceRequestRewriteFunction;
public FileServiceGatewayGlobalFilter(ModifyRequestBodyGatewayFilterFactory modifyRequestBodyGatewayFilterFactory,
FileServiceProperties fileServiceProperties,
FileServiceRequestRewriteFunction fileServiceRequestRewriteFunction) {
this.modifyRequestBodyGatewayFilterFactory = modifyRequestBodyGatewayFilterFactory;
this.fileServiceProperties = fileServiceProperties;
this.fileServiceRequestRewriteFunction = fileServiceRequestRewriteFunction;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
Route route = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);
if (route != null && route.getUri() != null && route.getUri().getHost().equalsIgnoreCase("file-service")) {
var requestPath = exchange.getRequest().getURI().getPath();
if (requestPath.equalsIgnoreCase(fileServiceProperties.getUploadTokenPath())) {
return modifyRequestBodyGatewayFilterFactory.apply(new ModifyRequestBodyGatewayFilterFactory()
.newConfig().setRewriteFunction(byte[].class, byte[].class, fileServiceRequestRewriteFunction))
.filter(exchange, chain);
}
}
return chain.filter(exchange);
}
static class UploadTokenRequest {
private String type;
private String bucket;
private String prefix;
private String fileKey;
private String sourceFile;
private Long sourceFileSize;
private String sourceFileType;
private Integer useSourceFilename;
private Long expiredInSec;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getBucket() {
return bucket;
}
public void setBucket(String bucket) {
this.bucket = bucket;
}
public String getPrefix() {
return prefix;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
public String getFileKey() {
return fileKey;
}
public void setFileKey(String fileKey) {
this.fileKey = fileKey;
}
public String getSourceFile() {
return sourceFile;
}
public void setSourceFile(String sourceFile) {
this.sourceFile = sourceFile;
}
public Long getSourceFileSize() {
return sourceFileSize;
}
public void setSourceFileSize(Long sourceFileSize) {
this.sourceFileSize = sourceFileSize;
}
public String getSourceFileType() {
return sourceFileType;
}
public void setSourceFileType(String sourceFileType) {
this.sourceFileType = sourceFileType;
}
public Integer getUseSourceFilename() {
return useSourceFilename;
}
public void setUseSourceFilename(Integer useSourceFilename) {
this.useSourceFilename = useSourceFilename;
}
public Long getExpiredInSec() {
return expiredInSec;
}
public void setExpiredInSec(Long expiredInSec) {
this.expiredInSec = expiredInSec;
}
}
static class OssUploadFile {
private String bucket;
private String prefix;
private String fileKey;
private String sourceFile;
private Long sourceFileSize;
private String sourceFileType;
private Integer useSourceFilename;
private Long expiredInSec;
public String getBucket() {
return bucket;
}
public void setBucket(String bucket) {
this.bucket = bucket;
}
public String getPrefix() {
return prefix;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
public String getFileKey() {
return fileKey;
}
public void setFileKey(String fileKey) {
this.fileKey = fileKey;
}
public String getSourceFile() {
return sourceFile;
}
public void setSourceFile(String sourceFile) {
this.sourceFile = sourceFile;
}
public Long getSourceFileSize() {
return sourceFileSize;
}
public void setSourceFileSize(Long sourceFileSize) {
this.sourceFileSize = sourceFileSize;
}
public String getSourceFileType() {
return sourceFileType;
}
public void setSourceFileType(String sourceFileType) {
this.sourceFileType = sourceFileType;
}
public Integer getUseSourceFilename() {
return useSourceFilename;
}
public void setUseSourceFilename(Integer useSourceFilename) {
this.useSourceFilename = useSourceFilename;
}
public Long getExpiredInSec() {
return expiredInSec;
}
public void setExpiredInSec(Long expiredInSec) {
this.expiredInSec = expiredInSec;
}
}
}
文件服务配置
import java.util.Map;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "file-service", ignoreUnknownFields = true)
public class FileServiceProperties {
private String uploadTokenPath;
private String defaultBucket;
private Map<String, String> typeBuckets;
public String getUploadTokenPath() {
return uploadTokenPath;
}
public void setUploadTokenPath(String uploadTokenPath) {
this.uploadTokenPath = uploadTokenPath;
}
public String getDefaultBucket() {
return defaultBucket;
}
public void setDefaultBucket(String defaultBucket) {
this.defaultBucket = defaultBucket;
}
public Map<String, String> getTypeBuckets() {
return typeBuckets;
}
public void setTypeBuckets(Map<String, String> typeBuckets) {
this.typeBuckets = typeBuckets;
}
}