Eric Bidelman, G Suite API'ler Ekibi
Şubat 2010
Giriş
Mevcut web standartları, büyük dosyaların HTTP yüklemesini kolaylaştırmak için güvenilir bir mekanizma sağlamamaktadır. Bu nedenle, Google'daki ve diğer sitelerdeki dosya yüklemeleri geleneksel olarak orta boyutla (ör. 100 MB) sınırlandırılmıştır. Bu, YouTube ve Google Dokümanlar Listesi API'leri gibi büyük dosya yüklemelerini destekleyen hizmetler için büyük bir engel teşkil eder.
Google Verileri devam ettirilebilir protokolü, devam ettirilebilir POST/PUT HTTP isteklerini HTTP/1.0'da destekleyerek yukarıda bahsedilen sorunları doğrudan ele alır. Protokol, Google Gear ekibi tarafından önerilen ResumableHttpRequestsBid parametresinden sonra modellenmiştir.
Bu dokümanda, Google Verileri'nin devam ettirilebilir yükleme özelliğinin uygulamalarınıza nasıl dahil edileceği açıklanmaktadır. Aşağıdaki örneklerde Google Dokümanlar Listesi Veri API'si kullanılmaktadır. Bu protokolü uygulayan ek Google API'lerinin, gereksinimleri/yanıt kodları/vb. arasında küçük farklar olabileceğini unutmayın. Ayrıntılar için lütfen hizmetin dokümanlarına bakın.
Devam Ettirilebilir Protokol
Devam ettirilebilir yükleme isteği başlatma
Devam ettirilebilir yükleme oturumu başlatmak için devam ettirilebilir gönderi bağlantısına bir HTTP POST
isteği gönderin. Bu bağlantı feed düzeyinde bulunur.
DocList API'nın devam ettirilebilir yayın bağlantısı şöyle görünür:
<link rel="http://schemas.google.com/g/2005#resumable-create-media" type="application/atom+xml" href="https://docs.google.com/feeds/upload/create-session/default/private/full"/>
POST
isteğinizin gövdesi boş olmalı veya Atom XML girişi içermeli ve gerçek dosya içeriğini içermemelidir.
Aşağıdaki örnekte büyük bir PDF yüklemek için devam ettirilebilir bir istek oluşturulmuştur ve Slug
başlığını kullanarak gelecekteki belge için bir başlık ekleyebilirsiniz.
POST /feeds/upload/create-session/default/private/full HTTP/1.1 Host: docs.google.com GData-Version: version_number Authorization: authorization Content-Length: 0 Slug: MyTitle X-Upload-Content-Type: content_type X-Upload-Content-Length: content_length empty body
X-Upload-Content-Type
ve X-Upload-Content-Length
başlıkları, daha sonra yükleyeceğiniz dosyanın mime türü ve boyutuna ayarlanmalıdır. Yükleme oturumu oluşturulduğunda içerik uzunluğu bilinmiyorsa X-Upload-Content-Length
başlığı atlanabilir.
Bunun yerine bir kelime dokümanı yükleyen başka bir örnek isteği burada görebilirsiniz. Bu kez Atom meta verileri dahil edilir ve son doküman girişine uygulanır.
POST /feeds/upload/create-session/default/private/full?convert=false HTTP/1.1
Host: docs.google.com
GData-Version: version_number
Authorization: authorization
Content-Length: atom_metadata_content_length
Content-Type: application/atom+xml
X-Upload-Content-Type: application/msword
X-Upload-Content-Length: 7654321
<?xml version='1.0' encoding='UTF-8'?>
<entry xmlns="http://www.w3.org/2005/Atom" xmlns:docs="http://schemas.google.com/docs/2007">
<category scheme="http://schemas.google.com/g/2005#kind"
term="http://schemas.google.com/docs/2007#document"/>
<title>MyTitle</title>
<docs:writersCanInvite value="false"/>
</entry>
Sunucunun ilk POST
yanıtı, Location
başlığında benzersiz bir yükleme URI'si ve boş bir yanıt gövdesidir:
HTTP/1.1 200 OK
Location: <upload_uri>
Dosya parçalarını yüklemek için benzersiz yükleme URI'si kullanılır.
Not: İlk POST
isteği, feed'de yeni bir giriş oluşturmaz.
Bu durum, yalnızca yükleme işleminin tamamı tamamlandığında gerçekleşir.
Not: Devam ettirilebilen oturum URI'sinin süresi bir hafta sonra dolar.
Dosya yükleme
İstek boyutlarıyla ilgili HTTP'de yerleşik herhangi bir kısıtlama olmadığından, devam ettirilebilir protokol içeriğin "parçalar"a yüklenmesine izin verir ancak zorunlu değildir. İstemciniz, parça boyutunu seçebilir veya dosyayı bir bütün olarak yükleyebilir.
Bu örnekte, devam ettirilebilir bir PUT
yayınlamak için benzersiz yükleme URI'si kullanılmaktadır. Aşağıdaki örnek 1234567 bayt PDF dosyasının ilk 100.000 baytını gönderir:
PUT upload_uri HTTP/1.1 Host: docs.google.com Content-Length: 100000 Content-Range: bytes 0-99999/1234567 bytes 0-99999
PDF dosyasının boyutu bilinmiyorsa bu örnekte Content-Range: bytes
0-99999/*
kullanılır. Content-Range
başlığı hakkında daha fazla bilgiyi
burada bulabilirsiniz.
Sunucu, depolanan mevcut bayt aralığıyla yanıt verir:
HTTP/1.1 308 Resume Incomplete Content-Length: 0 Range: bytes=0-99999
İstemciniz, dosyanın tamamı yüklenene kadar her dosya parçasına PUT
işlemi yapmaya devam etmelidir.
Yükleme işlemi tamamlanana kadar sunucu, HTTP 308 Resume Incomplete
ve bildiği bayt aralığını Range
başlığında bildirir. Müşteriler, bir sonraki parçaya nereden başlayacağını belirlemek için Range
üstbilgisini kullanmalıdır.
Bu nedenle, sunucunun PUT
isteğinde başlangıçta gönderilen tüm baytları aldığını varsaymayın.
Not: Sunucu, parça sırasında Location
başlığında yeni bir benzersiz yükleme URI'si yayınlayabilir. İstemciniz, güncellenmiş bir Location
olup olmadığını kontrol etmeli ve kalan URI'leri sunucuya göndermek için bu URI'yi kullanmalıdır.
Yükleme tamamlandığında yanıt, API'nin devam ettirilemeyen yükleme mekanizması kullanılarak yapılmış gibi yanıt verilir. Yani, 201 Created
tarafından sunucu tarafından oluşturulan <atom:entry>
ile birlikte döndürülür. Benzersiz yükleme URI'sine yapılan sonraki PUT
'ler, yükleme tamamlandığında döndürülen yanıtı döndürür.
Bir süre sonra yanıt 410 Gone
veya 404 Not Found
olur.
Yüklemeyi devam ettirme
İsteğiniz sunucudan yanıt almadan önce feshedilirse veya sunucudan bir HTTP 503
yanıtı alırsanız benzersiz yükleme URI'sinde boş bir PUT
isteği göndererek yüklemenin mevcut durumunu sorgulayabilirsiniz.
İstemci, aldığı baytları belirlemek için sunucuyu sorgular:
PUT upload_uri HTTP/1.1 Host: docs.google.com Content-Length: 0 Content-Range: bytes */content_length
Uzunluk bilinmiyorsa content_length olarak *
kullanın.
Sunucu, geçerli bayt aralığıyla yanıt verir:
HTTP/1.1 308 Resume Incomplete Content-Length: 0 Range: bytes=0-42
Not: Sunucu, oturum için bayt kullanmamışsa Range
başlığını çıkarır.
Not: Sunucu, parça sırasında Location
başlığında yeni bir benzersiz yükleme URI'si yayınlayabilir. İstemciniz, güncellenmiş bir Location
olup olmadığını kontrol etmeli ve kalan URI'leri sunucuya göndermek için bu URI'yi kullanmalıdır.
Son olarak istemci, sunucunun kaldığı yerden devam eder:
PUT upload_uri HTTP/1.1 Host: docs.google.com Content-Length: 57 Content-Range: 43-99/100 <bytes 43-99>
Yüklemeyi iptal etme
Yüklemeyi iptal edip başka bir işlem yapılmasını önlemek istiyorsanız benzersiz yükleme URI'sinde DELETE
isteği gönderin.
DELETE upload_uri HTTP/1.1 Host: docs.google.com Content-Length: 0
Başarılı olursa sunucu, oturumun iptal edildiğine ve daha sonra PUT
ya da sorgu durumu istekleri için aynı kodla yanıt verir:
HTTP/1.1 499 Client Closed Request
Not: Yükleme işlemi iptal edilmeden reddedilirse doğal olarak videonun süresi sona erdikten bir hafta sonra sona erer.
Mevcut bir kaynağı güncelleme
Devam ettirilebilir bir yükleme oturumu başlatmaya benzer şekilde, mevcut bir dosyanın içeriğini değiştirmek için devam ettirilebilir yükleme protokolünü kullanabilirsiniz. Devam ettirilebilir bir güncelleme isteği başlatmak için girişin bağlantısında rel='...#resumable-edit-media
' ile bir HTTP PUT
gönderin.
API, kaynağın içeriğini güncellemeyi destekliyorsa her medya entry
bunu içerir.
Örneğin, DocList API'deki bir belge girişi aşağıdakine benzer bir bağlantı içerir:
<link rel="http://schemas.google.com/g/2005#resumable-edit-media" type="application/atom+xml" href="https://docs.google.com/feeds/upload/create-session/default/private/full/document%3A12345"/>
İlk istek şöyle olur:
PUT /feeds/upload/create-session/default/private/full/document%3A12345 HTTP/1.1 Host: docs.google.com GData-Version: version_number Authorization: authorization If-Match: ETag | * Content-Length: 0 X-Upload-Content-Length: content_length X-Upload-Content-Type: content_type empty body
Bir kaynağın meta verilerini ve içeriğini aynı anda güncellemek için boş gövde yerine Atom XML ekleyin. Devam ettirilebilir bir yükleme isteği başlatma bölümündeki örneğe bakın.
Sunucu, benzersiz yükleme URI'si ile yanıt verdiğinde, yükünizle birlikte bir PUT
gönderin. Benzersiz yükleme URI'niz olduğunda, dosyanın içeriğini güncelleme süreci dosya yükleme ile aynıdır.
Bu örnek, mevcut dokümanın içeriğini tek bir çekimde güncelleyecektir:
PUT upload_uri HTTP/1.1 Host: docs.google.com Content-Length: 1000 Content-Range: 0-999/1000 <bytes 0-999>
İstemci kitaplığı örnekleri
Aşağıda, Google Veri istemci kitaplıklarındaki Google'a film yükleme örneği (devam ettirilebilir yükleme protokolü kullanılarak) verilmiştir. Şu anda tüm kitaplıkların devam ettirilebilir özelliğini desteklemediğini unutmayın.
int MAX_CONCURRENT_UPLOADS = 10; int PROGRESS_UPDATE_INTERVAL = 1000; int DEFAULT_CHUNK_SIZE = 10485760; DocsService client = new DocsService("yourCompany-yourAppName-v1"); client.setUserCredentials("user@gmail.com", "pa$$word"); // Create a listener FileUploadProgressListener listener = new FileUploadProgressListener(); // See the sample for details on this class. // Pool for handling concurrent upload tasks ExecutorService executor = Executors.newFixedThreadPool(MAX_CONCURRENT_UPLOADS); // Create {@link ResumableGDataFileUploader} for each file to upload Listuploaders = Lists.newArrayList(); File file = new File("test.mpg"); String contentType = DocumentListEntry.MediaType.fromFileName(file.getName()).getMimeType(); MediaFileSource mediaFile = new MediaFileSource(file, contentType); URL createUploadUrl = new URL("https://docs.google.com/feeds/upload/create-session/default/private/full"); ResumableGDataFileUploader uploader = new ResumableGDataFileUploader(createUploadUrl, mediaFile, client, DEFAULT_CHUNK_SIZE, executor, listener, PROGRESS_UPDATE_INTERVAL); uploaders.add(uploader); listener.listenTo(uploaders); // attach the listener to list of uploaders // Start the upload(s) for (ResumableGDataFileUploader uploader : uploaders) { uploader.start(); } // wait for uploads to complete while(!listener.isDone()) { try { Thread.sleep(100); } catch (InterruptedException ie) { listener.printResults(); throw ie; // rethrow }
// Chunk size in MB int CHUNK_SIZE = 1; ClientLoginAuthenticator cla = new ClientLoginAuthenticator( "yourCompany-yourAppName-v1", ServiceNames.Documents, "user@gmail.com", "pa$$word"); // Set up resumable uploader and notifications ResumableUploader ru = new ResumableUploader(CHUNK_SIZE); ru.AsyncOperationCompleted += new AsyncOperationCompletedEventHandler(this.OnDone); ru.AsyncOperationProgress += new AsyncOperationProgressEventHandler(this.OnProgress); // Set metadata for our upload. Document entry = new Document() entry.Title = "My Video"; entry.MediaSource = new MediaFileSource("c:\\test.mpg", "video/mpeg"); // Add the upload uri to document entry. Uri createUploadUrl = new Uri("https://docs.google.com/feeds/upload/create-session/default/private/full"); AtomLink link = new AtomLink(createUploadUrl.AbsoluteUri); link.Rel = ResumableUploader.CreateMediaRelation; entry.DocumentEntry.Links.Add(link); ru.InsertAsync(cla, entry.DocumentEntry, userObject);
- (void)uploadAFile { NSString *filePath = @"~/test.mpg"; NSString *fileName = [filePath lastPathComponent]; // get the file's data NSData *data = [NSData dataWithContentsOfMappedFile:filePath]; // create an entry to upload GDataEntryDocBase *newEntry = [GDataEntryStandardDoc documentEntry]; [newEntry setTitleWithString:fileName]; [newEntry setUploadData:data]; [newEntry setUploadMIMEType:@"video/mpeg"]; [newEntry setUploadSlug:fileName]; // to upload, we need the entry, our service object, the upload URL, // and the callback for when upload has finished GDataServiceGoogleDocs *service = [self docsService]; NSURL *uploadURL = [GDataServiceGoogleDocs docsUploadURL]; SEL finishedSel = @selector(uploadTicket:finishedWithEntry:error:); // now start the upload GDataServiceTicket *ticket = [service fetchEntryByInsertingEntry:newEntry forFeedURL:uploadURL delegate:self didFinishSelector:finishedSel]; // progress monitoring is done by specifying a callback, like this SEL progressSel = @selector(ticket:hasDeliveredByteCount:ofTotalByteCount:); [ticket setUploadProgressSelector:progressSel]; } // callback for when uploading has finished - (void)uploadTicket:(GDataServiceTicket *)ticket finishedWithEntry:(GDataEntryDocBase *)entry error:(NSError *)error { if (error == nil) { // upload succeeded } } - (void)pauseOrResumeUploadForTicket:(GDataServiceTicket *)ticket { if ([ticket isUploadPaused]) { [ticket resumeUpload]; } else { [ticket pauseUpload]; } }
import os.path import atom.data import gdata.client import gdata.docs.client import gdata.docs.data CHUNK_SIZE = 10485760 client = gdata.docs.client.DocsClient(source='yourCompany-yourAppName-v1') client.ClientLogin('user@gmail.com', 'pa$$word', client.source); f = open('test.mpg') file_size = os.path.getsize(f.name) uploader = gdata.client.ResumableUploader( client, f, 'video/mpeg', file_size, chunk_size=CHUNK_SIZE, desired_class=gdata.docs.data.DocsEntry) # Set metadata for our upload. entry = gdata.docs.data.DocsEntry(title=atom.data.Title(text='My Video')) new_entry = uploader.UploadFile('/feeds/upload/create-session/default/private/full', entry=entry) print 'Document uploaded: ' + new_entry.title.text print 'Quota used: %s' % new_entry.quota_bytes_used.text
Örneklerin tamamı ve kaynak kodu referansı için aşağıdaki kaynaklara bakın:
- Java kitaplığı örnek uygulaması ve kaynağı
- Object-C kitaplığı örnek uygulaması
- .NET kitaplığı kaynağı