perf: improve more friendly exception messages (#113)

```release-note
友好地提示异常信息
```
fixes https://github.com/halo-dev/plugin-s3/issues/105

验证方法:
1. ak/sk乱输,发生接收到403状态码(接收错误状态码)
2. endpoint网址改成不存在的,如.com改成.comaaa(未知主机)
3. endpoint端口改成没监听的(超时)
This commit is contained in:
longjuan
2024-01-16 22:14:12 +08:00
committed by GitHub
parent 82f409e349
commit 8ff4acba6e
4 changed files with 60 additions and 25 deletions

View File

@@ -0,0 +1,42 @@
package run.halo.s3os;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.server.ServerWebInputException;
import software.amazon.awssdk.core.exception.SdkException;
import software.amazon.awssdk.services.s3.model.S3Exception;
@Slf4j
@UtilityClass
public class S3ExceptionHandler {
/**
* Map user configuration caused S3 exception to ServerWebInputException
* @param throwable Exception
* @return ServerWebInputException or original exception
*/
public static Throwable map(Throwable throwable) {
if (throwable instanceof S3Exception s3e) {
log.error("S3Exception occurred", s3e);
return new ServerWebInputException(String.format(
"The object storage service returned an error status code %d. Please check the storage "
+ "policy configuration and make sure your account and service are working properly.",
s3e.statusCode()));
}
if (throwable instanceof SdkException sdke && sdke.getMessage() != null
&& sdke.getMessage().contains("UnknownHostException")) {
log.error("UnknownHostException occurred", sdke);
return new ServerWebInputException(
"Received an UnknownHostException, please check if the endpoint is entered correctly, "
+ "especially for any spaces before or after the endpoint.");
}
if (throwable instanceof SdkException sdke && sdke.getMessage() != null
&& sdke.getMessage().contains("Connect timed out")) {
log.error("ConnectTimeoutException occurred", sdke);
return new ServerWebInputException(
"Received a ConnectTimeoutException, please check if the endpoint is entered correctly, "
+ "and make sure your object storage service is working properly.");
}
return throwable;
}
}

View File

@@ -1,5 +1,13 @@
package run.halo.s3os;
import static run.halo.s3os.S3OsAttachmentHandler.OBJECT_KEY;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
@@ -9,38 +17,18 @@ import org.springframework.security.core.context.ReactiveSecurityContextHolder;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.stereotype.Service;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.util.UriUtils;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.core.scheduler.Schedulers;
import run.halo.app.core.extension.attachment.Attachment;
import run.halo.app.core.extension.attachment.Constant;
import run.halo.app.core.extension.attachment.Policy;
import run.halo.app.extension.ConfigMap;
import run.halo.app.extension.Metadata;
import run.halo.app.extension.ReactiveExtensionClient;
import run.halo.app.infra.utils.JsonUtils;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.S3Configuration;
import software.amazon.awssdk.services.s3.model.HeadObjectRequest;
import software.amazon.awssdk.services.s3.model.ListObjectsV2Request;
import software.amazon.awssdk.services.s3.model.S3Object;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.stream.Collectors;
import static run.halo.s3os.S3OsAttachmentHandler.OBJECT_KEY;
@Service
@RequiredArgsConstructor
@@ -103,7 +91,8 @@ public class S3LinkServiceImpl implements S3LinkService {
listObjectsV2Response.nextContinuationToken(),
listObjectsV2Response.isTruncated()));
});
});
})
.onErrorMap(S3ExceptionHandler::map);
}
@Override
@@ -155,7 +144,8 @@ public class S3LinkServiceImpl implements S3LinkService {
.getKey() : null, tokenState.currToken,
limitedObjects.size() == pageSize);
});
});
})
.onErrorMap(S3ExceptionHandler::map);
}
record TokenState(String currToken, String nextToken) {
@@ -200,6 +190,7 @@ public class S3LinkServiceImpl implements S3LinkService {
.flatMap(client::create)
.thenReturn(new LinkResult.LinkResultItem(objectKey, true, null));
}))
.onErrorMap(S3ExceptionHandler::map)
.onErrorResume(throwable ->
Mono.just(new LinkResult.LinkResultItem(objectKey, false, throwable.getMessage())));
}

View File

@@ -82,7 +82,8 @@ public class S3OsAttachmentHandler implements AttachmentHandler {
final var properties = getProperties(context.configMap());
return upload(context, properties)
.subscribeOn(Schedulers.boundedElastic())
.map(objectDetail -> this.buildAttachment(properties, objectDetail));
.map(objectDetail -> this.buildAttachment(properties, objectDetail))
.onErrorMap(S3ExceptionHandler::map);
});
}
@@ -116,6 +117,7 @@ public class S3OsAttachmentHandler implements AttachmentHandler {
})
.thenReturn(context);
})
.onErrorMap(S3ExceptionHandler::map)
.map(DeleteContext::attachment);
}
@@ -152,7 +154,8 @@ public class S3OsAttachmentHandler implements AttachmentHandler {
}
},
SdkPresigner::close)
.subscribeOn(Schedulers.boundedElastic());
.subscribeOn(Schedulers.boundedElastic())
.onErrorMap(S3ExceptionHandler::map);
}
@Override

View File

@@ -1,6 +1,5 @@
package run.halo.s3os;
import java.time.Instant;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;