Blobstore API允许你的应用程序使用(serve)叫做Blobs的数据对象。这种数据对象比Datastore服务所允许的对象的尺寸大得多。Blobs能有效地为大文件比如视频、图片提供服务,允许用户上传大数据文件。通过HTTP请求上传一个文件来创建Blobs。通常,你的应用程序通过向用户呈现一个表格(form)和一个文件上传区域(a file upload field)来实现。当这个表格被提交的时候,Blobstore会从文件的内容来创建一个Blob,并且返回一个指向blob的叫做blob key的不透明引用。在之后可以使用它使用(serve)这个blob。应用程序可以提供(serve)这个完整的blob值来响应用户的请求,或者可以使用一个类流文件接口(streaming file-like interface)直接读取blob值。
Blobstore简介
GAE包含了Blobstore服务,它允许应用使用(serve)数据对象,仅受限于数据的数量,可以通过一个HTTP连接上传下载。这些对象被叫做Blobstore values或blobs。Blobstore values 被作为来自请求处理的响应,通过Web forms上传时被创建(Blobstore values are served as response from request handlers and are created as uploads via web forms)。应用不直接创建Blob数据;blobs通过一个被提交的web form或HTTP post请求来间接创建的。Blobstore values可以被用户使用或者在类文件流中被应用访问。(使用Blobstore API)
注意:Blobstore服务创建的Blobs与datastore使用的blob属性值没有关系。
你的应用通过呈现一个web form和文件上传区域来提示用户上传一个Blobstore value。应用通过调用Blobstore API来产生表格的action URL。用户的浏览器通过这个生成的URL直接将文件上传到Blobstore。然后Blobstore存储这个blob,重写这个请求来包含这个blob key,将它传递到你的应用的一个路径。在你的应用的那个路径的一个请求处理可以执行额外的表格处理。
为了使用(serve)一个blob,你的应用在输出响应设置一个头部,App Engine会用这个blob value 取代这个响应。
Blobs在创建之后不能够被修改,但是可以被删除。每个blob有一个相应的blob info record。它被存储在datastore,包含了这个Blob的详细,比如它的创建时间和文本类型。你可以使用这个blob key去获取blob info record和查询他们的属性。
应用可以使用一个API调用,一次读取一个Blobstore value一部分。这个部分的尺寸可以是一个API返回值的最大尺寸。这个尺寸小于32M,在Java中由com.google.appengine.api.blobstore.BlobstoreService.MAX_BLOB_FETCH_SIZE表示。应用不能够创建和修改Blobstore values,除非用户上传文件。
使用Blobstore
应用可以使用Blobstore来接受来自用户上传的大文件以及使用(serve)这些文件。文件一旦被上传,其就被称为blobs。应用不直接访问blobs。而是通过在datastore中的blob info 实体一起工作(呈现为BlobInfo类)。
用户通过提交一个包含了一个或多个文件输入字段的HTML表格创建一个blob。你的应用设置 blobstoreService.createUploadUrl()
作为这个表格的目标地址(action),在应用中传递给这个函数一个处理(handler)的URL路径。当用户提交这个表格时,用户的浏览器直接上传指定的文件到Blobstore中。Blobstore重写用户的请求并且存储上传的文件数据,用一个或多个相应的blob key取代上传的文件数据,然后传递这个重写的请求到在你提供给blobstoreService.createUploadUrl()的URL上的处理(handler)。这个处理(handler)可以基于blob key来处理额外的处理(processing)。
应用可以使用类文件流接口读取Blobstore value的部分。参见BlobstoreInputStream类。
上传一个Blob
为了创建和上传一个blob,遵循以下步骤。
1.创建一个upload URL
调用blobstoreService.createUploadUrl()
来为用户将会填充的表格创建一个upload URL,当表格的Post完成时,传递这个应用的路径来加载。
<body> <form action="<%= blobstoreService.createUploadUrl("/upload") %>" method="post" enctype="multipart/form-data"> <input type="file" name="myFile"> <input type="submit" value="Submit"> </form> </body>
注意如果它是用JSP创建的话,这就是上传表格的样子。
2.创建一个上传表格
这个表格必须包含文件上传字段,表格的enctype必须被设置为multipart/form-data。当用户提交这个表格时,这个POST被Blobstore API处理,创建blob。这个API也为blob创建一个info record,并且将这个record存储在datastore中,在给定的路径上以blob key的形式传递这个重写请求到你的应用。
3.实现上传处理。
在这个处理中,你可以用你的应用的数据模型的其余部分存储blob key。这个blob key可以访问在datastore中的blob info实体。注意在用户提交表格以及你的处理被调用之后,这个blob已经被保存了,blob info被添加到了datastore。如果你的应用不想保留这个blob,你应当立即删除这个blob,防止它成为孤立的。
在下面的代码中,getUploads返回了已经上传的blobs集合。Map对象是一个列表,关联了上传字段的名字和blobs。
Map<String, List<BlobKey>> blobs = blobstoreService.getUploads(req); List<BlobKey> blobKeys = blobs.get("myFile"); if (blobKeys == null || blobKeys.isEmpty()) { res.sendRedirect("/"); } else { res.sendRedirect("/serve?blob-key=" + blobKeys.get(0).getKeyString()); }
当Blobstore重写用户的请求时,上传文件的MIME部分使他们的bodies清空,这个blob key被添加作为MIME部分的头。所有的其他表格字段和部分被保存、传递给上传处理(upload handler)。如果你不指定文本类型,Blobstore会尝试从文件的扩展名来推断。如果文本类型不能确定,这个新建的blob的文本类型被分配为application/octet-stream。
使用(serve)一个blob
注意:如果你使用(serve)图片,一个更有效、可能更便宜的方法是使用getServingUrl()使用App Engine images API而不是blobstoreService.serve().这个getServingUrl()方法可让你直接使用(serve)图片,不必通过你的App Engine实例。
为了使用(serve)blobs,在应用中你必须包含一个下载处理[as a path]。这个处理应当传递想要的blob的blob key到blobstoreService.serve(blobKey, res)。在这个例子中,这个blob key作为URL参数被传递给下载处理(req.getParameter('blob-key'))。在实践中,下载处理可以通过多种方式获得blob key。比如通过其他方法或用户操作(user action)。
public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException { BlobKey blobKey = new BlobKey(req.getParameter("blob-key")); blobstoreService.serve(blobKey, res);
Blobs can be served from any application URL. To serve a blob in your application, 在包含blob key的响应中放置一个特别的头。App Engine使用blob的文本取代响应的body。
Blob字节范围
Blobstore支持提供(serve)一个大值的部分而不是值的全部来响应一个请求。为了提供部分值,在输出响应中包含X-AppEngine-BlobRange头部。它的值是一个标准的HTTP字节范围。这个字节编号从0开始。空白的X-AppEngine-BlobRange指示API忽略这个范围头,提供整个blob。例子范围包括:
0-499提供value的前500字节。
500-999提供从第501个字节开始的500个字节。
500-提供从第501个字节开始到最后的所有字节。
-500提供value的最后500个字节。
如果这个字节范围对Blobstore value来讲是有效的话,那么Blobstore会发出一个206 partial Content状态代码和请求的字节范围到客户端。如果这个范围不是有效的,Blobstore会发出416 Requested Range Not Satisfiable。
Blobstore不支持在一个请求中的多字节范围(比如,100-199,200-299),无论他们是否重叠。
完整的例子应用
在接下来的例子应用中,应用的主URL加载向用户寻求文件上传的表格,上传处理立即调用下载处理来提供(serve)数据。这是为了简化例子应用。在实践中,你可能不使用主URL来请求上传数据,也不立即提供你刚刚上传的blob。
// file Upload.java import java.io.IOException; import java.util.List; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.google.appengine.api.blobstore.BlobKey; import com.google.appengine.api.blobstore.BlobstoreService; import com.google.appengine.api.blobstore.BlobstoreServiceFactory; public class Upload extends HttpServlet { private BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService(); @Override public void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { Map<String, List<BlobKey>> blobs = blobstoreService.getUploads(req); List<BlobKey> blobKeys = blobs.get("myFile"); if (blobKeys == null || blobKeys.isEmpty()) { res.sendRedirect("/"); } else { res.sendRedirect("/serve?blob-key=" + blobKeys.get(0).getKeyString()); } } } // file Serve.java import java.io.IOException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.google.appengine.api.blobstore.BlobKey; import com.google.appengine.api.blobstore.BlobstoreService; import com.google.appengine.api.blobstore.BlobstoreServiceFactory; public class Serve extends HttpServlet { private BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService(); @Override public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException { BlobKey blobKey = new BlobKey(req.getParameter("blob-key")); blobstoreService.serve(blobKey, res); } } // file index.jsp <%@ page import="com.google.appengine.api.blobstore.BlobstoreServiceFactory" %> <%@ page import="com.google.appengine.api.blobstore.BlobstoreService" %> <% BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService(); %> <html> <head> <title>Upload Test</title> </head> <body> <form action="<%= blobstoreService.createUploadUrl("/upload") %>" method="post" enctype="multipart/form-data"> <input type="text" name="foo"> <input type="file" name="myFile"> <input type="submit" value="Submit"> </form> </body> </html> // web.xml <?xml version="1.0" encoding="utf-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> <servlet> <servlet-name>Upload</servlet-name> <servlet-class>Upload</servlet-class> </servlet> <servlet> <servlet-name>Serve</servlet-name> <servlet-class>Serve</servlet-class> </servlet> <servlet-mapping> <servlet-name>Upload</servlet-name> <url-pattern>/upload</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>Serve</servlet-name> <url-pattern>/serve</url-pattern> </servlet-mapping> </web-app>
和Blobstore一起使用Images服务
Images服务可以使用Blobstore value作为转换的源。源图像(source image)可以和Blobstore value的最大尺寸一样大。Image服务依然返回转换后的图像到应用,所以转换后的图像必须小于32M。这对于生成用户上传的大图像的缩略图是有用的。
关于和Blobstore一起使用Image服务的信息,参见Image Service documentation。
和Google Cloud Storage一起使用Blobstore API
你可以使用Blobstore API将blobs存在在Google Cloud Storage而不是Blobstore中。你需要创建一个在Google Cloud Storage文档中称为bucket的东西。在BlobstoreService createUploadUrl中指定这个bucket,在UploadOptions参数中指定bucket名称。在你的上传处理(upload handler)中,你需要处理这个返回的FileInfo元数据,以及显示地存储Google Cloud Storage文件名。这个文件名在之后需要用来取回blob。
你也可以使用Blobstore API使用Google Cloud Storage。下面的代码片段展示了如何实现:
这个例子是在一个请求处理中,在这个请求中获取了bucket名字和对象名。它创建了Blobstore service,使用它以及提供的bucket和对象名创建用于Google Cloud Storage的blob key。
BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService(); BlobKey blobKey = blobstoreService.createGsBlobKey( "/gs/" + fileName.getBucketName() + "/" + fileName.getObjectName()); blobstoreService.serve(blobKey, resp);
Note: Once you obtain a blobKey
for the Google Cloud Storage object, you can pass it around, serialize it, and otherwise use it interchangeably anywhere you can use a blobKey
for objects stored in Blobstore. This allows for usage where an app stores some data in blobstore and some in Google Cloud Storage, but treats the data otherwise identically by the rest of the app. (However, BlobInfo
objects are currently not available for Google Cloud Storage objects.)
使用Files API将文件写到Blobstore(已过时)
警告:此处使用的写文件到Blobstore的Files API已经过时了,将会被移除。参见Files API Service Turndown
。。。。。。
配额和限制
Blobstore values的使用空间contributes to Stored Data(计费)的配额。
在datastore中的Blob info entities 数量是datastore相关的限制。
整个系统的安全配额参见Quotas,the Administration Console的Quota Details部分。
为了整个系统的安全配额,对于Blobstore的使用有一个限制。可以被应用一次API调用读取的Blobstore数据的最大尺寸是32M。