Arka plan
Service Worker, web geliştiricilerinin web uygulamaları tarafından yapılan ağ isteklerine yanıt vermelerine, çevrimdışıyken bile çalışmaya devam etmelerine, lie-fi ile mücadele etmesine ve eski-tekrar doğrulama gibi karmaşık önbellek etkileşimleri uygulamasına olanak tanır. Ancak Service Worker'lar geçmişte belirli bir kaynağa bağlıdır. Bir web uygulamasının sahibi olarak, web uygulamanızın gönderdiği tüm ağ isteklerine müdahale etmek için bir hizmet çalışanı yazıp dağıtmak sizin sorumluluğunuzdadır. Bu modelde her hizmet çalışanı, üçüncü taraf API'leri veya web yazı tipleri gibi kaynaklar arası istekleri bile ele almaktan sorumludur.
Bir API'nin, web yazı tiplerinin ya da yaygın olarak kullanılan başka bir hizmetin üçüncü taraf sağlayıcısı, diğer kaynaklardan gelen istekleri kendi kaynağına gönderme fırsatı bulan kendi servis çalışanlarını dağıtma gücüne sahip olsaydı ne olacak? Sağlayıcılar kendi özel ağ iletişimi mantığını uygulayabilir ve yanıtlarını depolamak için tek, yetkili bir önbellek örneğinden yararlanabilir. Artık yabancı getirme sayesinde bu tür bir üçüncü taraf hizmet çalışanı dağıtımı artık mümkün.
Yabancı getirme uygulayan bir hizmet çalışanının dağıtılması, tarayıcılardan HTTPS istekleri aracılığıyla erişilen herhangi bir hizmetin sağlayıcısı için anlamlıdır. Hizmetinizin ağdan bağımsız bir sürümünü sağlayabileceğiniz ve tarayıcıların ortak kaynak önbelleğinden yararlanabileceği senaryoları düşünün. Bu durumdan yararlanabilecek hizmetler aşağıda belirtilmiştir, ancak bunlarla sınırlı değildir:
- RESTful arayüze sahip API sağlayıcılar
- Web yazı tipi sağlayıcıları
- Analiz sağlayıcıları
- Resim barındırma sağlayıcıları
- Genel içerik yayınlama ağları
Örneğin, bir analiz sağlayıcısı olduğunuzu düşünün. Yabancı bir getirme hizmeti çalışanı dağıtarak, kullanıcı çevrimdışıyken hizmetinize yönelik başarısız olan tüm isteklerin kuyruğa alınmasını ve bağlantı geri geldiğinde tekrar oynatılmasını sağlayabilirsiniz. Bir hizmetin istemcilerinin birinci taraf hizmet çalışanları aracılığıyla benzer bir davranış uygulaması mümkün olsa da her istemcinin hizmetiniz için özel mantık yazmasını zorunlu kılmak, dağıttığınız paylaşılan bir yabancı getirme hizmeti çalışanına güvenmek kadar ölçeklenebilir değildir.
Ön koşullar
Kaynak Deneme jetonu
Yabancı dil getirme işlemi hâlâ deneysel olarak kabul edilir. Bu tasarımın, tarayıcı tedarikçileri tarafından tam olarak belirtilmeden ve kabul edilmeden erkenden işlenmesini önlemek için Chrome 54'te Kaynak Denemesi olarak uygulanmıştır. Yabancı getirme deneysel olduğu sürece, bu yeni özelliği barındırdığınız hizmetle kullanmak için hizmetinizin belirli kaynağına ayarlanmış bir jeton istemeniz gerekir. Bu jeton, yabancı getirme aracılığıyla işlemek istediğiniz kaynakların tüm çapraz kaynak isteklerine ve hizmet çalışanı JavaScript kaynağınıza verilen yanıta HTTP yanıt başlığı olarak eklenmelidir:
Origin-Trial: token_obtained_from_signup
Deneme süresi Mart 2017'de sona erecektir. Bu noktaya kadar, özelliği kararlı hale getirmek için gerekli değişiklikleri tespit etmiş ve (umuyoruz) özelliği varsayılan olarak etkinleştirmiş olacağız. Bu tarihe kadar yabancı getirme varsayılan olarak etkinleştirilmemişse mevcut Kaynak Deneme jetonlarına bağlı işlevler çalışmayı durdurur.
Resmi Kaynak Deneme jetonuna kaydolmadan önce yabancı getirme denemesi yapmayı kolaylaştırmak için chrome://flags/#enable-experimental-web-platform-features
adresine gidip "Deneysel Web Platformu özellikleri" işaretini etkinleştirerek yerel bilgisayarınız için Chrome şartını atlayabilirsiniz. Bu işlemin, yerel denemelerinizde kullanmak istediğiniz her Chrome örneğinde yapılması gerektiğini, Kaynak Deneme jetonuyla ise özelliğin tüm Chrome kullanıcılarınız tarafından kullanılabileceğini lütfen unutmayın.
HTTPS
Tüm hizmet çalışanı dağıtımlarında olduğu gibi, hem kaynaklarınızı hem de hizmet çalışanı komut dosyanızı sunmak için kullandığınız web sunucusuna HTTPS üzerinden erişilmelidir. Ayrıca, yabancı getirme müdahalesi yalnızca güvenli kaynaklarda barındırılan sayfalardan gelen istekler için geçerlidir. Bu nedenle, hizmetinizin istemcilerinin yabancı getirme uygulamanızdan yararlanmak için HTTPS kullanması gerekir.
Yabancı Getirme'yi Kullanma
Önkoşullar ortadan kalktıktan sonra, bir yabancı getirme hizmeti çalışanının hazır ve çalışır duruma gelmesi için gerekli teknik ayrıntılara girelim.
Hizmet çalışanınız kaydediliyor
Karşılaşabileceğiniz ilk zorluk, hizmet çalışanınızı nasıl kaydedeceğinizdir. Daha önce Service Worker'larla çalıştıysanız aşağıdaki konuları muhtemelen biliyorsunuzdur:
// You can't do this!
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('service-worker.js');
}
Birinci taraf hizmet çalışanı kaydı için oluşturulan bu JavaScript kodu, kullanıcının kontrol ettiğiniz bir URL'ye gitmesiyle tetiklenen bir web uygulaması bağlamında anlamlıdır. Ancak, sunucunuzla tek etkileşim tarayıcısı tam gezinme değil, belirli bir alt kaynak isteğinde bulunduğunda bu, üçüncü taraf hizmet çalışanı kaydettirmeye uygun bir yaklaşım değildir. Tarayıcı, örneğin yönettiğiniz bir CDN sunucusundan resim isterse bu JavaScript snippet'ini yanıtınızın başına ekleyemez ve çalıştırılmasını bekleyemezsiniz. Normal JavaScript yürütme bağlamı dışında farklı bir hizmet çalışanı kayıt yöntemi gereklidir.
Çözüm, sunucunuzun herhangi bir yanıta ekleyebileceği bir HTTP üstbilgisi biçiminde gelir:
Link: </service-worker.js>; rel="serviceworker"; scope="/"
Bu örnek başlığı, her biri bir ;
karakteriyle ayrılan bileşenlerine ayıralım.
</service-worker.js>
gereklidir ve hizmet çalışanı dosyanızın yolunu belirtmek için kullanılır (/service-worker.js
ifadesinin yerine komut dosyanızın uygun yolunu girin). Normaldenavigator.serviceWorker.register()
öğesine ilk parametre olarak iletilecek olanscriptURL
dizesine doğrudan karşılık gelir. Değerin<>
karakterleri içine alınması gerekir (Link
başlık spesifikasyonunun gerektirdiği gibi) ve mutlak URL yerine göreli bir URL sağlanırsa yanıtın konumuna göre yorumlanır.rel="serviceworker"
de gereklidir ve özelleştirmeye gerek kalmadan dahil edilmelidir.scope=/
,navigator.serviceWorker.register()
öğesine ikinci parametre olarak iletebileceğinizoptions.scope
dizesine eşdeğer olan, isteğe bağlı bir kapsam bildirimidir. Çoğu kullanım alanında varsayılan kapsamı kullanmanız sorun yaratmaz. Dolayısıyla ihtiyacınız olduğunu bilmiyorsanız bu alanı dışarıda bırakabilirsiniz. İzin verilen maksimum kapsamla ilgili kısıtlamalar veService-Worker-Allowed
başlığı aracılığıyla bu kısıtlamaları gevşetme seçeneğinin yanı sıraLink
başlık kayıtları için de geçerlidir.
"Geleneksel" hizmet çalışanı kaydında olduğu gibi, Link
başlığı kullanıldığında da kayıtlı kapsamda yapılan sonraki istek için kullanılacak bir hizmet çalışanı yüklenir. Özel başlığı içeren yanıtın gövdesi olduğu gibi kullanılır ve yabancı hizmet çalışanının kurulumu tamamlaması beklenmeden sayfaya hemen erişilebilir.
Yabancı getirmenin şu anda bir Kaynak Denemesi olarak uygulandığını unutmayın. Bu nedenle, Bağlantı yanıtı başlığınızla birlikte geçerli bir Origin-Trial
üstbilgisi de eklemeniz gerekir. Yabancı dil getirme hizmeti çalışanınızı kaydetmek için eklenecek minimum yanıt başlığı kümesi:
Link: </service-worker.js>; rel="serviceworker"
Origin-Trial: token_obtained_from_signup
Hata ayıklama kaydı
Geliştirme sırasında, muhtemelen yabancı getirme hizmeti çalışanınızın düzgün şekilde yüklendiğini ve istekleri işlediğini onaylamak isteyebilirsiniz. İşlerin beklendiği gibi çalıştığını doğrulamak için Chrome'un Geliştirici Araçları'nda kontrol edebileceğiniz birkaç şey vardır.
Doğru yanıt üstbilgileri gönderiliyor mu?
Yabancı getirme hizmeti çalışanını kaydetmek için alan adınızda barındırılan bir kaynağa verilen yanıtta, bu yayının önceki bölümlerinde açıklandığı gibi bir Bağlantı üstbilgisi ayarlamanız gerekir. Kaynak Deneme süresi boyunca ve ayarlanmış chrome://flags/#enable-experimental-web-platform-features
olmadığını varsayarsak bir Origin-Trial
yanıt başlığı da ayarlamanız gerekir. DevTools'un Ağ paneli'ndeki girişe bakarak web sunucunuzun bu üstbilgileri ayarladığını doğrulayabilirsiniz:
Yabancı Getirme hizmeti çalışanı düzgün şekilde kaydedildi mi?
Geliştirici Araçları'nın Uygulama panelinde, hizmet çalışanlarının tam listesine bakarak kapsamı da dahil olmak üzere temel hizmet çalışanı kaydını onaylayabilirsiniz. Varsayılan olarak yalnızca geçerli kaynağa ait hizmet çalışanlarını göreceğiniz için "Tümünü göster" seçeneğini işaretlediğinizden emin olun.
Yükleme etkinlik işleyicisi
Üçüncü taraf hizmet çalışanınızı kaydettirdiğinize göre bu çalışan, diğer hizmet çalışanı gibi install
ve activate
etkinliklerine yanıt verme fırsatına sahip olacak. Örneğin, install
etkinliği sırasında önbellekleri gerekli kaynaklarla doldurmak veya activate
etkinliğindeki güncel olmayan önbellekleri ayıklamak için bu etkinliklerden yararlanabilir.
Normal install
etkinliklerini önbelleğe alma etkinliklerinin ötesinde, üçüncü taraf hizmet çalışanınızın install
etkinlik işleyicisinde zorunlu ek bir adım vardır. Kodunuzun aşağıdaki örnekte olduğu gibi registerForeignFetch()
yöntemini çağırması gerekir:
self.addEventListener('install', event => {
event.registerForeignFetch({
scopes: [self.registration.scope], // or some sub-scope
origins: ['*'] // or ['https://example.com']
});
});
İki yapılandırma seçeneği vardır ve her ikisi de gereklidir:
scopes
, bir veya daha fazla dizeden oluşan bir dizi alır. Bu dizelerin her biri,foreignfetch
etkinliğini tetikleyecek isteklerin kapsamını temsil eder. Ama bir dakika, Hizmet çalışanı kaydı sırasında zaten bir kapsam tanımladım şeklinde düşünebilirsiniz. Genel kapsam da geçerliliğini korur. Burada belirttiğiniz her kapsam, hizmet çalışanının genel kapsamına eşit veya onun bir alt kapsamı olmalıdır. Buradaki ek kapsam kısıtlamaları, hem birinci taraffetch
etkinliklerini (kendi sitenizden yapılan istekler için) hem de üçüncü tarafforeignfetch
etkinliklerini (diğer alanlardan yapılan istekler için) işleyebilen çok amaçlı bir hizmet çalışanı dağıtmanıza ve daha geniş kapsamınızın yalnızca bir alt kümesininforeignfetch
etkinliğini tetikleyeceğini açıkça belirtmenize olanak tanır. Pratikte yalnızca üçüncü tarafforeignfetch
etkinliklerini işlemeye özel bir hizmet çalışanı dağıtıyorsanız yalnızca hizmet çalışanınızın genel kapsamına eşit olan tek ve açık bir kapsam kullanmanız gerekir. Yukarıdaki örnek,self.registration.scope
değerini kullanarak bu işlemi gerçekleştirecektir.origins
ayrıca bir veya daha fazla dizeden oluşan bir dizi alır veforeignfetch
işleyicinizi yalnızca belirli alan adlarından gelen isteklere yanıt verecek şekilde kısıtlamanıza olanak tanır. Örneğin, "https://example.com"a açıkça izin verirseniz yabancı getirme kapsamınızdan sunulan bir kaynak içinhttps://example.com/path/to/page.html
adresinde barındırılan bir sayfadan yapılan istek, yabancı getirme işleyicinizi tetikler ancakhttps://random-domain.com/path/to/page.html
uygulamasından yapılan istekler işleyicinizi tetiklemez. Uzak kaynakların yalnızca bir alt kümesi için yabancı getirme mantığınızı tetiklemek üzere belirli bir nedeniniz yoksa dizideki tek değer olarak'*'
değerini belirtebilirsiniz. Bu durumda tüm kaynaklara izin verilir.
yabancı Getirme etkinlik işleyicisi
Üçüncü taraf hizmet çalışanınızı yüklediğinize ve registerForeignFetch()
aracılığıyla yapılandırıldığına göre artık sunucunuza yapılan, yabancı getirme kapsamına giren kaynaklar arası alt kaynak isteklerine müdahale etme fırsatı elde edeceksiniz.
Geleneksel birinci taraf Service Worker'da her istek, hizmet çalışanınızın yanıt verebileceği bir fetch
etkinliğini tetikler. Üçüncü taraf hizmet çalışanımıza foreignfetch
adlı biraz farklı bir etkinliği gerçekleştirme şansı verildi. Kavramsal olarak bu iki etkinlik oldukça benzerdir ve size gelen isteği inceleme ve isteğe bağlı olarak respondWith()
aracılığıyla yanıt verme fırsatı sunar:
self.addEventListener('foreignfetch', event => {
// Assume that requestLogic() is a custom function that takes
// a Request and returns a Promise which resolves with a Response.
event.respondWith(
requestLogic(event.request).then(response => {
return {
response: response,
// Omit to origin to return an opaque response.
// With this set, the client will receive a CORS response.
origin: event.origin,
// Omit headers unless you need additional header filtering.
// With this set, only Content-Type will be exposed.
headers: ['Content-Type']
};
})
);
});
Kavramsal benzerliklere rağmen, ForeignFetchEvent
üzerinde respondWith()
çağrılırken uygulama açısından birkaç farklılık vardır. respondWith()
için yalnızca bir Response
(veya Response
ile çözümlenen Promise
) sağlamak yerine, FetchEvent
ile çözülür gibi, ForeignFetchEvent
öğesinin respondWith()
öğesine belirli özelliklere sahip bir nesneyle çözümlenen Promise
değerini iletmeniz gerekir:
response
gerekli ve isteği gönderen istemciye döndürülecekResponse
nesnesi olarak ayarlanmalıdır. Geçerli birResponse
dışında bir bilgi sağlarsanız istemcinin isteği ağ hatasıyla sonlandırılır. Birfetch
etkinlik işleyicinin içinderespondWith()
çağırmanın aksine, burada birResponse
sağlamanız zorunludur,Response
ile çözümlenenPromise
değeri yerine! Yanıtınızı bir taahhüt zinciri aracılığıyla oluşturabilir ve bu zinciri,foreignfetch
respondWith()
nesnesine parametre olarak aktarabilirsiniz. Ancak zincirin,Response
nesnesine ayarlanmışresponse
özelliğini içeren bir Nesne ile çözümlenmesi gerekir. Bunun bir örneğini yukarıdaki kod örneğinde görebilirsiniz.origin
isteğe bağlıdır ve döndürülen yanıtın opak olup olmadığını belirlemek için kullanılır. Bunu dışarıda bırakırsanız yanıt opak olur ve istemci, yanıtın gövdesine ve başlıklarına sınırlı şekilde erişebilir. İstekmode: 'cors'
ile yapıldıysa opak yanıt döndürülmesi hata olarak değerlendirilir. Ancak, uzak istemcinin kaynağına (event.origin
aracılığıyla edinilebilir) eşit bir dize değeri belirtirseniz, istemciye CORS özellikli bir yanıt sağlama özelliğini açıkça etkinleştirirsiniz.headers
de isteğe bağlıdır ve yalnızcaorigin
özelliğini belirtiyor ve bir CORS yanıtı döndürüyorsanız kullanışlıdır. Varsayılan olarak, yanıtınıza yalnızca CORS güvenli listedeki yanıt başlığı listesindeki başlıklar dahil edilir. Döndürülen içeriğe daha fazla filtre uygulamanız gerekirse üstbilgiler, bir veya daha fazla üstbilgi adının yer aldığı bir listeyi alır. Bu liste, yanıtta gösterilecek üstbilgilerin izin verilenler listesi olarak kullanılır. Bu sayede, CORS'u etkinleştirirken hassas olabilecek yanıt başlıklarının doğrudan uzak istemciye gösterilmesini önlersiniz.
foreignfetch
işleyici çalıştırıldığında, hizmet çalışanını barındıran kaynağın tüm kimlik bilgilerine ve ortam yetkililerine erişimi olduğunu aklınızda bulundurun. Yabancı bir getirme özelliğinin etkin olduğu hizmet çalışanı dağıtan bir geliştirici olarak, söz konusu kimlik bilgileri aracılığıyla başka şekilde erişilemeyecek ayrıcalıklı yanıt verilerini sızdırmadığınızdan emin olmak sizin sorumluluğunuzdadır. CORS yanıtlarının etkinleştirilmesini zorunlu kılmak, yanlışlıkla maruz kalmayı sınırlamanın bir adımıdır ancak bir geliştirici olarak foreignfetch
işleyicinizin içinde, aşağıdakiler aracılığıyla ima edilen kimlik bilgilerini kullanmayan açıkça fetch()
isteklerinde bulunabilirsiniz:
self.addEventListener('foreignfetch', event => {
// The new Request will have credentials omitted by default.
const noCredentialsRequest = new Request(event.request.url);
event.respondWith(
// Replace with your own request logic as appropriate.
fetch(noCredentialsRequest)
.catch(() => caches.match(noCredentialsRequest))
.then(response => ({response}))
);
});
Müşteriler için dikkat edilmesi gereken noktalar
Yabancı getirme hizmeti çalışanınızın, hizmetinizin istemcilerinden gelen istekleri işleme şeklini etkileyen bazı ek hususlar vardır.
Kendi birinci taraf hizmet çalışanı olan müşteriler
Hizmetinizdeki bazı istemcilerin, web uygulamalarından gelen istekleri ele alan kendilerine ait birinci taraf hizmet çalışanları zaten olabilir. Bu, üçüncü taraf, yabancı getirme hizmeti çalışanınız için ne anlama geliyor?
Birinci taraf hizmet çalışanının fetch
işleyicileri, foreignfetch
özelliğine sahip ve isteği kapsayan bir kapsama sahip üçüncü taraf hizmet çalışanı olsa bile web uygulaması tarafından yapılan tüm isteklere yanıt vermek için ilk fırsatı elde eder. Ancak birinci taraf hizmet çalışanları olan müşteriler, yabancı getirme hizmeti çalışanınızdan yararlanmaya devam edebilir.
Birinci taraf hizmet çalışanı içinde, kaynaklar arası kaynakları almak için fetch()
kullanmak uygun yabancı getirme hizmeti çalışanını tetikler. Bu durumda, aşağıdaki gibi bir kod foreignfetch
işleyicinizden yararlanabilir:
// Inside a client's first-party service-worker.js:
self.addEventListener('fetch', event => {
// If event.request is under your foreign fetch service worker's
// scope, this will trigger your foreignfetch handler.
event.respondWith(fetch(event.request));
});
Benzer şekilde, birinci taraf getirme işleyicileri varsa ancak bu işleyiciler çapraz kaynak kaynağınızla ilgili istekleri işlerken event.respondWith()
yöntemini çağırmıyorsa istek otomatik olarak foreignfetch
işleyicinize "yedek" olarak geçer:
// Inside a client's first-party service-worker.js:
self.addEventListener('fetch', event => {
if (event.request.mode === 'same-origin') {
event.respondWith(localRequestLogic(event.request));
}
// Since event.respondWith() isn't called for cross-origin requests,
// any foreignfetch handlers scoped to the request will get a chance
// to provide a response.
});
Birinci taraf fetch
işleyici event.respondWith()
çağırır ancak yabancı getirme kapsamınız kapsamında kaynak istemek için fetch()
hizmetini kullanmazsa yabancı getirme hizmeti çalışanınızın isteği işleme fırsatı olmaz.
Kendi hizmet çalışanı olmayan istemciler
Üçüncü taraf hizmetlerine istek gönderen tüm istemciler, hizmet bir yabancı getirme hizmeti çalışanı dağıttığında kendi hizmet çalışanını kullanmıyor olsalar bile bundan yararlanabilir. Destekleyen bir tarayıcı kullandıkları sürece, yabancı getirme hizmeti çalışanlarını kullanmaya başlamak için istemcilerin yapmaları gereken özel bir işlem yoktur. Bu, yabancı bir getirme hizmeti çalışanının dağıtımının, özel istek mantığınızın ve paylaşılan önbelleğinizin, hizmetinizin birçok istemcisine herhangi bir işlem gerçekleştirmeden, anında fayda sağlayacağı anlamına gelir.
Her şeyi bir araya getirmek: Müşterilerin yanıt aradığı yer
Yukarıdaki bilgileri göz önünde bulundurarak, bir istemcinin çapraz kaynak isteklerine yanıt bulmak için kullanacağı kaynak hiyerarşisini bir araya getirebiliriz.
- Birinci taraf hizmet çalışanının
fetch
işleyicisi (varsa) - Üçüncü taraf hizmet çalışanının
foreignfetch
işleyicisi (varsa ve yalnızca kaynaklar arası istekler için) - Tarayıcının HTTP önbelleği (yeni bir yanıt varsa)
- Ağ
Tarayıcı tepeden başlar ve hizmet çalışanının uygulamasına bağlı olarak yanıtın kaynağını bulana kadar listede ilerlemeye devam eder.
Daha fazla bilgi
En son gelişmeleri kaçırmayın
Geliştiricilerden gelen geri bildirimler doğrultusunda Chrome'un yabancı getirme Kaynak Denemesi uygulaması değişebilir. Satır içi değişiklikler yoluyla bu yayını güncel tutacağız ve aşağıdaki belirli değişiklikleri yapıldıkça not edeceğiz. Ayrıca @chromiumdev Twitter hesabı üzerinden önemli değişikliklerle ilgili bilgileri de paylaşacağız.