Как зарегистрировать сервисного работника из разных поддоменов

У меня есть два субдомена типа https://abc.xxxx.com и https://xyz.xxxx.com Так мои вопросы:

1). возможно ли зарегистрировать сервисного работника для https://xyz.xxxx.com из https://abc.xxxx.com? если да, то как?

2). если http://abc.xxxx.com ( http небезопасно), то в любом случае зарегистрироваться сервисный рабочий для https://xyz.xxxx.com из http://abc.xxxx.com в iframe или что-то еще....

Это реальная ситуация, я столкнулся со своим несколькими субдоменами. Любая помощь оценивается. Спасибо заранее

Ответ 1

Вот некоторые общие ответы, которые, я думаю, должны затрагивать различные моменты, которые вы поднимаете в своем вопросе:

  • У каждого зарегистрированного сервисного работника есть связанный scope, который диктует набор веб-страниц, которые может обслуживать рабочий сервис, Рабочий столбец scope - это URL-адрес, и этот URL-адрес должен иметь тот же источник, что и страница, на которой регистрируется рабочий службы, и должен быть либо URL-адресом, который соответствует тому же уровню пути, что и страница, или путь, или больше уровней вниз. Значение по умолчанию scope соответствует тому же уровню пути, что и местоположение рабочего-оператора script. Из-за этого ограничения невозможно вызывать navigator.serviceWorker.register(...) со страницы в одном (под) домене и в конечном итоге с рабочим сервисом, который управляет страницами в другом (суб) домене.

  • Существуют ограничения, запрещающие вам бросать https: <iframe> на странице http: и использовать это для регистрации рабочего. См. DOMException при регистрации рабочего рабочего внутри https iframe

  • Хотя я не знаю, что он напрямую связан с вашим вопросом, явный вызов fetch() для ресурса http: в вашем рабочем рабочем коде будет приводить к сбою в текущих версиях Chrome, содержимое fetch() не разрешено в пределах рабочего. Я не знаю, установлены ли на этом фронте 100%, и эта открытая ошибка по-прежнему актуальна.

Если у вас есть страницы, которые живут как на abc.123.com, так и xyz.123.com, и вы хотите, чтобы оба набора страниц контролировались сотрудником службы, вам необходимо иметь две отдельные регистрации рабочих сервисов. Каждая регистрация должна быть для копии вашего JS файла службы поддержки, размещенного в соответствующем домене, соответствующем странице верхнего уровня, и все страницы и сценарии рабочего стола должны быть доступны через https:.

При этом вы можете запустить регистрацию сервисного работника для другого домена, включив кросс-домен <iframe> на странице, но как для главной страницы, так и для <iframe> для обслуживания через https:. Применяются ограничения на обладание обычными рабочими службами, поэтому, если вы хотите, например, зарегистрировать сотрудника службы для другого домена, который будет охватывать всю область https://other-domain.com/, вам необходимо убедиться, что местоположение рабочего-сервиса script регистрируется на верхнем уровне, например https://other-domain.com/service-worker.js, а не в https://other-domain.com/path/to/service-worker.js. Это подход, используемый, например, проект AMP через <amp-install-serviceworker>.

Ответ 2

Service Worker scripts must be hosted at the same origin (Protocol + Domain name + Port). Каждый поддомен считается другим источником, поэтому вам нужно будет зарегистрировать сервисного работника для каждого из них. Каждый из этих рабочих будет иметь свои собственные cache и scope.

Ответ 3

Мой плохой, я неправильно понял. Ну вот код

if('serviceWorker' in navigator){
    if(window.location.pathname != '/'){
        //register with API
        if(!navigator.serviceWorker.controller) navigator.serviceWorker.register('/service-worker', { scope: '/' });
        //once registration is complete
        navigator.serviceWorker.ready.then(function(serviceWorkerRegistration){
            //get subscription
            serviceWorkerRegistration.pushManager.getSubscription().then(function(subscription){

                //enable the user to alter the subscription
                //jquery selector for enabling whatever you use to subscribe.removeAttr("disabled");
                //set it to allready subscribed if it is so
                if(subscription){
                    //code for showing the user that they're allready subscribed
                }
            });
        });
    }   
}else{  
    console.warn('Service workers aren\'t supported in this browser.');  
}

то здесь event -ish для вашей подписки/отписки

// subscribe or unsubscribe to the ServiceWorker
$(document.body).on('change', /*selector*/, function(){
    //new state is checked so we subscribe
    if($(this).prop('checked')){
        navigator.serviceWorker.ready.then(function(serviceWorkerRegistration){
            serviceWorkerRegistration.pushManager.subscribe()  
                .then(function(subscription){  
                    // The subscription was successful  
                    console.log('subscription successful'); //subscription.subscriptionId

                    //save in DB - this is important because 
                    $.post($('#basePath').val() + 'settings/ajax-SW-sub/', {id:subscription.subscriptionId}, function(data){
                        //console.log(data);
                    }, 'json');

                    }).catch(function(e) {  
                        if (Notification.permission === 'denied') {  
                            // The user denied the notification permission which  
                            // means we failed to subscribe and the user will need  
                            // to manually change the notification permission to  
                            // subscribe to push messages
                            console.warn('Permission for Notifications was denied');
                        } else {  
                            // A problem occurred with the subscription; common reasons  
                            // include network errors, and lacking gcm_sender_id and/or  
                            // gcm_user_visible_only in the manifest.  
                            console.error('Unable to subscribe to push.', e);
                        }  
                    });  
        });//*/
    //new state us unchecked so we unsubscribe
    }else{
        $('.js-enable-sub-test').parent().removeClass('checked');
        //get subscription
        navigator.serviceWorker.ready.then(function(reg) {
            reg.pushManager.getSubscription().then(function(subscription) {
                //unregister in db
                $.post($('#basePath').val() + 'settings/ajax-SW-unsub/', {id:subscription.subscriptionId}, function(data){
                    //console.log(data);
                }, 'json');

                //remove subscription from google servers
                subscription.unsubscribe().then(function(successful) {
                    // You've successfully unsubscribed
                    console.log('unsubscribe successful');
                }).catch(function(e) {
                    // Unsubscription failed
                    console.log('unsubscribe failed', e);
                })
            })        
        });//*/
    }
});

после этого вам необходимо зарегистрировать учетную запись на консоли разработчика Google и зарегистрировать проект для чего-то вроде *.xxxx.com. Затем вам нужно получить правильный манифест json с gcm_sender_id и gcm_user_visible_only

Вам нужно создать ключ для приложений сервера и браузера, там больше информации об этом на этой странице.

https://developers.google.com/web/updates/2015/03/push-notificatons-on-the-open-web?hl=en

Тот, который для приложений браузера находится в вашем манифесте json.

Затем для отправки push-уведомлений вы будете использовать что-то вроде этого:

  function addSWmessage($args){

    $output = false;

    if(!isset($args['expiration']) || $args['expiration'] == ''){
        $args['expiration'] = date('Y-m-d H:i:s', strtotime('+7 days', time()));
    }

    $sql = sprintf("INSERT INTO `serviceworker_messages` SET title = '%s', body = '%s', imageurl = '%s', linkurl = '%s', hash = '%s', expiration = '%s'",
                    parent::escape_string($args['title']),
                    parent::escape_string($args['text']),
                    parent::escape_string($args['imageurl']),
                    parent::escape_string($args['linkurl']),
                    parent::escape_string(md5(uniqid('******************', true))),
                    parent::escape_string($args['expiration']));

    if($id = parent::insert($sql)){
        $output = $id;
    }

    return $output;

}
function pushSWmessage($args){

    //$args['messageid'] $args['userids'][]

    foreach($args['userids'] as $val){

        $sql = sprintf("SELECT messages_mobile, messages FROM `users_serviceworker_hash` WHERE users_id = '%s'",
                        parent::escape_string($val));

        if($row = parent::queryOne($sql)){
            $m1 = json_decode($row['messages'], true);
            $m1[] = $args['messageid'];
            $m2 = json_decode($row['messages_mobile'], true);
            $m2[] = $args['messageid'];

            $sql = sprintf("UPDATE `users_serviceworker_hash` SET messages = '%s', messages_mobile = '%s' WHERE users_id = '%s'",
                            parent::escape_string(json_encode($m1)),
                            parent::escape_string(json_encode($m2)),
                            parent::escape_string($val['users_id']));

            parent::insert($sql);
        }
    }

    $sql = sprintf("SELECT subscriptionID, users_id FROM `users_serviceworker_subscriptions`");

    if($rows = parent::query($sql)){

        foreach($rows as $val){
            if(in_array($val['users_id'], $args['userids'])){
                $registrationIds[] = $val['subscriptionID'];
            }
        }
        if(isset($registrationIds) && !empty($registrationIds)){
            // prep the bundle
            $msg = array
            (
                'message'       => '!',
                'title'         => '!',
                'subtitle'      => '!',
                'tickerText'    => '!',
                'vibrate'       => 1,
                'sound'         => 1,
                'largeIcon'     => '!',
                'smallIcon'     => '!'
            );

            $headers = array
            (
                'Authorization: key='.SW_API_ACCESS_KEY,
                'Content-Type: application/json'
            );

            $fields = array
            (
                'registration_ids'  => $registrationIds,
                'data'              => $msg
            );

            $ch = curl_init();
            curl_setopt($ch,CURLOPT_URL, 'https://android.googleapis.com/gcm/send');
            curl_setopt($ch,CURLOPT_POST, true);
            curl_setopt($ch,CURLOPT_HTTPHEADER, $headers);
            curl_setopt($ch,CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch,CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch,CURLOPT_POSTFIELDS, json_encode($fields));
            curl_exec($ch);
            curl_close($ch);
        }
    }

}

И нет, я не знаю, какую проблему у вас возникла, но это работает для меня с несколькими субдоменами.:)