从 Amazon S3 提供资源的惯用 Wicket 方式
Idiomatic Wicket way of serving resources from Amazon S3
从 AWS S3 提供用户上传资产的 Wicket 方式是什么?
要求:
- 没有从浏览器到S3的直接请求;所有流量都通过我们的服务器代理;
- 允许浏览器缓存资源并清除缓存(通过校验和或数据库中的
version
字段);
- 资产仅提供给授权用户。
我可以想到以下解决方案:
用于解析 URL 并流式传输资产的所有资源的单个 SharedResource:
// resource definition:
mountResources("/assets/${path}", new ResourceReference("assets") {
public IResource getResource() {
return new AbstractResource() {
public ResourceResponse newResourceResponse(RequestAttribute attributes) {
String path = attributes.getParameters().get("path").toString()
// request S3 and stream the content
// handle caching / busting by hand
}
}
}
})
// Usage:
page.add(new Image("image", new SharedResourceReference("assets"), new PageParameters().add("path", "image.jpg"))
为每个资产创建一个新的 ResourceReference 并将其直接传递给图像。通过让 Resource 实现 IStaticCacheableResource:
来插入 Wicket 的缓存
class S3ResourceReference extends ResourceReference {
private String path;
public S3ResourceReference(String path) { ... }
public IResource getResource() {
return new S3Resource(path);
}
}
class S3Resource extends AbstractResource implements IStaticCacheableResource {
public S3ResourceStream getResourceStream() {
S3Object object = getObject(path);
return new S3ResourceStream(object);
}
public ResourceResponse newResourceResponse(Attributes attributes) {
S3ResourceStream stream = getResourceStream();
// populate response
}
}
class S3ResourceStream extends AbstractResourceStream {
S3ResourceStream(S3Object object) {
// ...
}
public InputStream getInputStream() { return object.objectContent }
// override metadata methods
}
// Usage:
page.add(new Image("image"), new S3ResourceReference("image.jpg"));
这些方法中哪种看起来更地道?
在第二个代码段中使用 IStaticCacheableResource 是否存在任何缺陷?
以下是这两种方法的区别:
页面实例锁定
- 在 1) 中,对资源的请求是针对应用程序范围的资源
- 在 2) 中,请求是针对页面范围的资源
在第二种情况下,Wicket 将在提供资源期间锁定对页面实例的访问。出于这个原因,我更喜欢使用应用程序范围的资源。
IStaticCacheableResource
如果资源实现此接口,则 Wicket 会将生成的 url 分解为资源,并在其文件名中添加类似 -123456789
的内容。这个散列是开发模式下的资源修改时间和生产模式下的 MD5 校验和。这有助于缓存。
我希望您意识到可以混合使用 1) 和 2) - 应用程序范围的资源引用 + IStaticCacheableResource。
还有一件事:我通常使用 new MyResourceReference()
而不是 new SharedResourceReference("the-name")
。
从 AWS S3 提供用户上传资产的 Wicket 方式是什么?
要求:
- 没有从浏览器到S3的直接请求;所有流量都通过我们的服务器代理;
- 允许浏览器缓存资源并清除缓存(通过校验和或数据库中的
version
字段); - 资产仅提供给授权用户。
我可以想到以下解决方案:
用于解析 URL 并流式传输资产的所有资源的单个 SharedResource:
// resource definition: mountResources("/assets/${path}", new ResourceReference("assets") { public IResource getResource() { return new AbstractResource() { public ResourceResponse newResourceResponse(RequestAttribute attributes) { String path = attributes.getParameters().get("path").toString() // request S3 and stream the content // handle caching / busting by hand } } } }) // Usage: page.add(new Image("image", new SharedResourceReference("assets"), new PageParameters().add("path", "image.jpg"))
为每个资产创建一个新的 ResourceReference 并将其直接传递给图像。通过让 Resource 实现 IStaticCacheableResource:
来插入 Wicket 的缓存class S3ResourceReference extends ResourceReference { private String path; public S3ResourceReference(String path) { ... } public IResource getResource() { return new S3Resource(path); } } class S3Resource extends AbstractResource implements IStaticCacheableResource { public S3ResourceStream getResourceStream() { S3Object object = getObject(path); return new S3ResourceStream(object); } public ResourceResponse newResourceResponse(Attributes attributes) { S3ResourceStream stream = getResourceStream(); // populate response } } class S3ResourceStream extends AbstractResourceStream { S3ResourceStream(S3Object object) { // ... } public InputStream getInputStream() { return object.objectContent } // override metadata methods } // Usage: page.add(new Image("image"), new S3ResourceReference("image.jpg"));
这些方法中哪种看起来更地道?
在第二个代码段中使用 IStaticCacheableResource 是否存在任何缺陷?
以下是这两种方法的区别:
页面实例锁定
- 在 1) 中,对资源的请求是针对应用程序范围的资源
- 在 2) 中,请求是针对页面范围的资源
在第二种情况下,Wicket 将在提供资源期间锁定对页面实例的访问。出于这个原因,我更喜欢使用应用程序范围的资源。
IStaticCacheableResource
如果资源实现此接口,则 Wicket 会将生成的 url 分解为资源,并在其文件名中添加类似 -123456789
的内容。这个散列是开发模式下的资源修改时间和生产模式下的 MD5 校验和。这有助于缓存。
我希望您意识到可以混合使用 1) 和 2) - 应用程序范围的资源引用 + IStaticCacheableResource。
还有一件事:我通常使用 new MyResourceReference()
而不是 new SharedResourceReference("the-name")
。