Я сгенерировал URL-адрес, подобный этому, для моих пользователей, чтобы получить файлы изображений из моего ведра aws s3:
Иногда пользователь может обновить страницу, и URL-адрес того же ресурса получит новый набор значений для Expires и Signature.
Браузер будет рассматривать эти два URL-адреса как два разных объекта и снова попытается загрузить ресурс из корзины s3.
Это вызывает проблемы с производительностью. Можно ли заставить браузер осознавать тот факт, что, несмотря на различие в параметрах части URL-адреса, пользователь пытается получить тот же ресурс и, следовательно, извлечь его из своего локального кеша?





У меня была такая же проблема, и я решил ее кешированием ссылок с предварительно подписанными URL-адресами изображений, это решит проблему.
Когда вы запрашиваете предварительно подписанный URL-адрес из AWS, он возвращает ссылку с истечением срока действия и подписью, которая указывает на исходный файл в вашей корзине, каждый раз, когда вы делаете обновление: сервер передает запрос в AWS, а затем получает новый срок действия и подпись, о которой браузер ничего не знает, поэтому он снова получит то же изображение.
Чтобы указать браузеру, что вы не хотите получать это снова, нужно отправить ту же подпись при обновлении страницы! Звучит просто, но может получиться беспорядочно, так что потерпите меня.
Решение, которое я сделал, заключалось в использовании слоя кэша "Редис", который отображает загруженные браузером изображения в сериал.
Если userA загружает страницу, вы просто проверяете, посещалась ли она раньше тем же пользователем и тем же браузером и MacAddress / IP, используя «серийный номер», который вы должны добавить в локальное хранилище браузера,
последовательная структура = (тип браузера и имя + userID + MacAddress / IP), это необходимо для того, чтобы убедиться, что он работает, если userA входит в систему с разных устройств и браузеров одновременно, и чтобы вы создавали один и тот же серийный номер каждый раз, когда userA загружает страницу / изображения из этого конкретного браузера и устройства.
Если у пользователя A нет серийного номера, сохраненного в локальном хранилище, добавьте его в локальное хранилище и перейдите проверьте, существует ли серийник в Redis (пользователь, возможно, вошел в систему раньше и очистил кеш браузера), если да, то удалите прикрепленный объект, который содержит предварительно подписанные ссылки для вашего изображения как параметры:
"serial" :
{
imageID_1 : "https://s3.bucket.xxx/imageID_1.jpg?.......xyz1",
imageID_2 : "https://s3.bucket.xxx/imageID_2.jpg?.......xyz2",
imageID_3 : "https://s3.bucket.xxx/imageID_3.jpg?.......xyz3"
}
Затем запросите новый предварительно подписанный URL-адрес для каждого идентификатора изображения / ключа, который должен быть загружен на страницу, и прикрепите их к параметрам «серийного» объекта в Redis. Если нет, то просто добавьте оба параметра "серийный" + объект:
"serial" :
{
imageID_1 : "https://s3.bucket.xxx/imageID_1.jpg?.......abc1",
imageID_2 : "https://s3.bucket.xxx/imageID_2.jpg?.......abc2",
imageID_3 : "https://s3.bucket.xxx/imageID_3.jpg?.......abc3"
}
если в браузере есть серийный номер, кэшированный в локальное хранилище, вы также должны проверять с каждым запросом, существует ли imageID в параметрах объекта, связанных с серийным номером чтобы создать для него заранее подписанный URL (если он не существует), добавьте его в качестве нового параметра к объекту:
"serial" :
{
imageID_1 : "https://s3.bucket.xxx/imageID_1.jpg?.......abc1",
imageID_2 : "https://s3.bucket.xxx/imageID_2.jpg?.......abc2",
imageID_3 : "https://s3.bucket.xxx/imageID_3.jpg?.......abc3",
imageID_4 : "https://s3.bucket.xxx/imageID_4.jpg?.......abc4",
}
это в случае, если у пользователя уже есть серийный номер, сохраненный в локальном хранилище браузеров, сообщающий, что ранее были загружены изображения, поэтому мы должны проверить, запрашивает ли пользователь A те же изображения, загруженные ранее, или он запрашивает новые.
наконец, вы должны проверить, не загружены ли изображения или запрещен ли доступ к ним из браузера по какой-либо причине (код конца шрифта для проверки и отправки отчета на сервер), в этом случае вы просто удаляете прикрепленный серийный объект и прикрепляете новый предварительно подписанные URL-адреса затем отправьте их обратно во внешний интерфейс (браузер).
Если у вас есть возможность изменить приложение на стороне сервера, вы можете создавать заголовки авторизации вместо создания заранее заданных URL-адресов.
См .: 5219165
Чтобы сделать это с помощью AWS Java SDK 2, вам потребуется специальная реализация Signer, которая также реализует Presigner. Вот тот, который я создал для выполнения работы, которая делегируется AwsS3V4Signer, который выполняет необходимые вычисления и является общедоступным API.
import org.springframework.stereotype.Component;
import software.amazon.awssdk.auth.signer.AwsS3V4Signer;
import software.amazon.awssdk.auth.signer.AwsSignerExecutionAttribute;
import software.amazon.awssdk.auth.signer.params.Aws4PresignerParams;
import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
import software.amazon.awssdk.core.signer.Presigner;
import software.amazon.awssdk.core.signer.Signer;
import software.amazon.awssdk.http.SdkHttpFullRequest;
import java.time.Clock;
import java.time.Instant;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
@Component
public class CustomAwsSigner implements Signer, Presigner {
private final AwsS3V4Signer theSigner = AwsS3V4Signer.create();
@Override
public SdkHttpFullRequest presign(final SdkHttpFullRequest request, final ExecutionAttributes executionAttributes) {
Instant baselineInstant = Instant.now().truncatedTo(ChronoUnit.HOURS);
final Aws4PresignerParams signingParams = Aws4PresignerParams.builder()
.awsCredentials(executionAttributes.getAttribute(AwsSignerExecutionAttribute.AWS_CREDENTIALS))
.signingName(executionAttributes.getAttribute(AwsSignerExecutionAttribute.SERVICE_SIGNING_NAME))
.signingRegion(executionAttributes.getAttribute(AwsSignerExecutionAttribute.SIGNING_REGION))
.signingClockOverride(Clock.fixed(baselineInstant, ZoneId.of("UTC")))
.expirationTime(baselineInstant.plus(1, ChronoUnit.HOURS))
.build();
return theSigner.presign(request, signingParams);
}
@Override
public SdkHttpFullRequest sign(final SdkHttpFullRequest request, final ExecutionAttributes executionAttributes) {
throw new UnsupportedOperationException("this class is only used for presigning");
}
}
Получить необходимые комплектующие для проводки авто.
@Configuration
public class S3ClientConfiguration {
@Bean
public S3Client amazonS3Client(final AwsCredentialsProvider credentialsProvider, AwsRegionProvider regionProvider) {
return S3Client.builder()
.credentialsProvider(credentialsProvider)
.region(regionProvider.getRegion())
.build();
}
@Bean
public AwsCredentialsProvider credentialsProvider() {
return DefaultCredentialsProvider.create();
}
@Bean
public S3Presigner presigner(final AwsCredentialsProvider credentialsProvider, AwsRegionProvider regionProvider) {
return S3Presigner.builder()
.credentialsProvider(credentialsProvider)
.region(regionProvider.getRegion())
.build();
}
@Bean
public AwsRegionProvider regionProvider() {
return DefaultAwsRegionProviderChain.builder().build();
}
}
Чтобы получить URL-адрес с истекающим сроком действия
@Autowired
private S3Presigner s3Presigner;
/**
* Convert an S3 URI to a normal HTTPS URI that expires.
*
* @param s3Uri S3 URI (e.g. s3://mybucketname/ArchieTest/フェニックス.jpg)
* @return https URI
*/
@SneakyThrows
public URI getExpiringUri(final URI s3Uri) {
final GetObjectRequest getObjectRequest =
GetObjectRequest.builder()
.bucket(s3Uri.getHost())
.key(s3Uri.getPath().substring(1))
.overrideConfiguration(builder -> {
builder.signer(awsSigner);
})
.build();
final GetObjectPresignRequest getObjectPresignRequest = GetObjectPresignRequest.builder()
.signatureDuration(Duration.ofSeconds(0)) // required, but ignored
.getObjectRequest(getObjectRequest)
.build();
return s3Presigner.presignGetObject(getObjectPresignRequest).url().toURI();
}
Вам не нужно помещать какую-либо логику кеширования redis или какую-либо сложную логику, чтобы помочь кешировать предварительно подписанный URL.
Чтобы заставить браузер использовать кеш, нам нужно только сделать один и тот же URL-адрес для нескольких запросов. В нашем случае предварительно подписанный URL для того же файла будет отличаться только подписью. Так что нам просто нужно сделать подпись идентичной.
И подпись создается на основе срока годности.
Таким образом, чтобы сделать подпись идентичной и, таким образом, сделать идентичными URL-адреса, вы можете передать одинаковый срок действия для всех предварительно подписанных запросов на создание URL-адресов для одного и того же файла, запрошенного в определенном временном окне.
Скажем, если мы передадим один и тот же срок действия для всех вызовов с предварительной подписью для file A в течение 10 минут, тогда все эти URL-адреса будут иметь одинаковую подпись (и, следовательно, тот же URL-адрес) и, следовательно, будут кэшированы.
CloudFront с подписанными cookie-файлами вместо предварительно заданных URL-адресов может работать лучше в этом случае docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/…