Firebase 云消息传递 - Django - 我如何服务工作者?
Firebase Cloud Messaging - Django - how do I service worker?
更新自浅见处:
我已经阅读了很多关于 Service Workers 的文章,并且推进了我正在从事的项目,远远超过了我写这篇文章时的水平。
我在这里探索的主要问题(从域的根获得 firebase-messaging-sw.js
服务)已由下面的 ServiceWorkerView
解决。
有趣的事实:事实证明,firebase-messaging-sw.js
从域的根目录提供服务的原因是 Service Worker 的控制范围由 URL 定义。所以,同时:
http://whatever.com/firebase-messaging-sw.js
掌控一切,
http://whatever.com/static/firebase-messaging-sw.js
只能控制 /static/
下的所有内容(在这种情况下,只有 Django 提供的静态资源)。即使JS文件是静态的,它也需要控制该路径之外的页面。
A good starting point for learning about Service Workers
原题:
如何让 FCM service worker (firebase-messaging-sw.js
) 在 Django 中工作?
我正在使用 django
和 fcm-django
。
如何在根目录中提供 firebase-messaging-sw.js
?
Django 默认在路径“/static/”下提供静态资源。将 STATIC_URL 更改为“/”使 firebase-messaging-sw.js
可用,但没有其他任何东西..
我尝试了将以下内容放入我的 urls.py 中的建议:
url(r'^(?!/static/.*)(?P<path>.*\..*)$', RedirectView.as_view(url='/static/%(path)s'))
虽然显然是对正则表达式魔法的光荣使用,但事实证明服务工作者不能支持重定向。 (我想这也与有趣的事实有关)
我在 urlconf 中写了一个显式 URL 指向的视图。行得通。
class ServiceWorkerView(View):
def get(self, request, *args, **kwargs):
return render(request, 'fcmtest/firebase-messaging-sw.js')
urls.py:
path('firebase-messaging-sw.js', views.ServiceWorkerView.as_view(), name='service_worker')
现在 url http://localhost:8000/firebase-messaging-sw.js
服务于 javascript;然而,Firebase 抱怨内容类型是 text/plain
所以我将视图更改为:
class ServiceWorkerView(View):
def get(self, request, *args, **kwargs):
return render(request, 'fcmtest/firebase-messaging-sw.js', content_type="application/x-javascript")
我得到的错误是:
Uncaught (in promise) TypeError: Failed to register a ServiceWorker: A
bad HTTP response code (404) was received when fetching the script.
我的firebase-messaging-sw.js
(注释none of the console.log statements print):
importScripts("https://www.gstatic.com/firebasejs/5.2.0/firebase-app.js");
importScripts("https://www.gstatic.com/firebasejs/5.2.0/firebase-messaging.js");
importScripts("https://www.gstatic.com/firebasejs/5.2.0/init.js");
// Initialize Firebase
var config = {
apiKey: "AIzaSyBOb5gh1Lry84116M1uvAS_xnKtcWUoNlA",
authDomain: "pyfcm-5f794.firebaseapp.com",
databaseURL: "https://pyfcm-5f794.firebaseio.com",
projectId: "pyfcm-5f794",
storageBucket: "pyfcm-5f794.appspot.com",
messagingSenderId: "813943398064"
};
console.log('in service worker - before initializeApp')
firebase.initializeApp(config);
console.log('in service worker - after initializeApp')
const messaging = firebase.messaging();
console.log('in service worker - after firebase.messaging')
// if the app is in the background (user not on page)
messaging.setBackgroundMessageHandler(function(payload) {
console.log('in service worker - in setBackgroundMessageHandler')
const title = "Hello World";
const options = {
body: payload.data.status
}
return self.registration.showNotification(title, options);
});
最后是我的设备注册页面(我不确定如何 运行 javascript 然后提交。form.submit() 没有用,但那可能是因为其他事情不起作用..?
(fcm/fcmtest/templates/fcmtest/device_registration.html
):
<head>
{% load static %}
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>FCM Device Registration</title>
<!-- update the version number as needed -->
<script src="https://www.gstatic.com/firebasejs/5.2.0/firebase.js"></script>
<script>
// Initialize Firebase
var config = {
apiKey: "AIzaSyBOb5gh1Lry84116M1uvAS_xnKtcWUoNlA",
authDomain: "pyfcm-5f794.firebaseapp.com",
databaseURL: "https://pyfcm-5f794.firebaseio.com",
projectId: "pyfcm-5f794",
storageBucket: "pyfcm-5f794.appspot.com",
messagingSenderId: "813943398064"
};
firebase.initializeApp(config);
</script>
<script defer src="https://www.gstatic.com/firebasejs/5.2.0/firebase-app.js"></script>
<!-- include only the Firebase features as you need -->
<script defer src="https://www.gstatic.com/firebasejs/5.2.0/firebase-auth.js"></script>
<!--<script defer src="https://www.gstatic.com/firebasejs/5.2.0/firebase-database.js"></script>-->
<script defer src="https://www.gstatic.com/firebasejs/5.2.0/firebase-messaging.js"></script>
<!--<script defer src="https://www.gstatic.com/firebasejs/5.2.0/firebase-storage.js"></script>-->
<!-- initialize the SDK after all desired features are loaded -->
<!--<script defer src="https://www.gstatic.com/firebasejs/5.2.0/init.js"></script>-->
</head>
<body>
<script>
function deviceRegistration() {
console.log('in deviceRegistration()')
firebase.initializeApp(config);
const messaging = firebase.messaging();
// public key generated in firebase console
messaging.usePublicVapidKey("BMEoHrnzLq5WNeyahbSxJNTyS-44bXug2wetxAWVMLMSUIQE0dexhP4pJhcSA-ZlQlneHURmYQcnq9ofym_sStY");
// console.log('{% static "firebase-messaging-sw.js" %}')
console.log("/firebase-messaging-sw.js")
// changed location passed to navigator.serviceWorker.register since I am no longer serving firebase-messaging.js from localhost/static/ (see that url hack)
// navigator.serviceWorker.register('{% static "firebase-messaging-sw.js" %}')
navigator.serviceWorker.register("/firebase-messaging-sw.js")
.then((registration) => {
console.log('before messaging.useServiceWorker')
messaging.useServiceWorker(registration);
console.log('after messaging.useServiceWorker')
// Request permission and get token.....
messaging.requestPermission()
.then(function(){
console.log("Have Permission");
})
.then(function(token) {
form = document.getElementById("registration_form");
registration_token = messaging.getToken();
form.registration_id = registration_token;
var isAndroid = navigator.userAgent.toLowerCase().indexOf("android") >= -1;
if (isAndroid) {
form.type = "android";
} else {
var isiOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
if (isiOS) {
form.type = "ios";
} else {
form.type = "web";
}
}
//form.submit();
})
.catch(function(err){
console.log("Permission denied");
})
});
// request permission to send notifications
messaging.requestPermission()
.then(function(){
console.log("Have Permission");
})
.then(function(token) {
form = document.getElementById("registration_form");
registration_token = messaging.getToken();
form.registration_id = registration_token;
var isAndroid = navigator.userAgent.toLowerCase().indexOf("android") >= -1;
if (isAndroid) {
form.type = "android";
} else {
var isiOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
if (isiOS) {
form.type = "ios";
} else {
form.type = "web";
}
}
//form.submit();
})
.catch(function(err){
console.log("Permission denied");
})
// if user is on the page then show message directly instead of a notification
messaging.onMessage(function(payload) {
console.log('payload: ', payload);
});
}
</script>
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<form id="registration_form" method="post">{% csrf_token %}
<input id="name" type="text" />
<input id="type" type="hidden" />
<input id="user" type="hidden" value="{{ user.id }}" />
<input id="registration_id" type="hidden" />
<input id="btn_register" type="button" value="Register" onclick="deviceRegistration();" />
</form>
</body>
我尝试按照以下说明添加 manifest.json
https://firebase.google.com/docs/cloud-messaging/js/client
它目前由我的静态文件提供,并在注册和发送页面中链接
我的控制台中的错误:
Uncaught (in promise) TypeError: Failed to register a ServiceWorker: A
bad HTTP response code (404) was received when fetching the script.
A bad HTTP response code (404) was received when fetching the script.
Failed to load resource: net::ERR_INVALID_RESPONSE
firebase-messaging-sw.js:3 Uncaught
(anonymous) @ firebase-messaging-sw.js:3
index.esm.js:1945 未捕获(承诺)
Object
browserErrorMessage:
"Failed to register a ServiceWorker: ServiceWorker script evaluation failed"
代码:
"messaging/failed-serviceworker-registration"
留言:
"Messaging: We are unable to register the default service worker. Failed to register a ServiceWorker: ServiceWorker script evaluation failed (messaging/failed-serviceworker-registration)."
堆栈:
"FirebaseError: Messaging: We are unable to register the default service worker. Failed to register a ServiceWorker: ServiceWorker script evaluation failed (messaging/failed-serviceworker-registration).↵ at https://www.gstatic.com/firebasejs/5.2.0/firebase-messaging.js:1:34104"
无法为 firebase-messaging-sw.js
提供服务的问题可以通过直接创建 ServiceWorkerView
到 GET
文件并硬编码 URLconf
.[=25 来解决=]
fcm/fcmtest/views.py:
class ServiceWorkerView(View):
def get(self, request, *args, **kwargs):
return render(request, 'fcmtest/firebase-messaging-sw.js', content_type="application/x-javascript")
fcm/fcmtest/urls.py
app_name = 'fcmtest'
urlpatterns = [
...
path('firebase-messaging-sw.js', views.ServiceWorkerView.as_view(), name='service_worker')
]
从域的根目录提供服务 firebase-messaging-sw.js
的原因是 Service Worker 的控制范围由 URL 路径定义。 Service Worker 可用路径下的所有内容都在其控制之下。
404
可能是由于 device_registration.html
中的 javascript 错误。 config
已被引用但尚未分配给。
function deviceRegistration() {
firebase.initializeApp(config);
此外,使用 Firebase 云消息传递没有必要(甚至可能有问题):
navigator.serviceWorker.register("/firebase-messaging-sw.js")
.then((registration) => {
messaging.useServiceWorker(registration);
})
而是使用 firebase.initializeApp(config);
在根目录下服务 manifest.json
可能是个好主意。
form.submit()
的问题在于,用于根据 promise 更改表单中的元素的代码不完整。调试后它会很好用。
我喜欢 Inversus 所做的事情,因为它会在 dev/test/prod 中发挥作用。也就是说,在生产中我选择让 nginx 为 firebase-messaging-sw.js 文件提供服务。 . .
# Firebase Cloud Messaging (FCM) requires this file to be served from
# your root directory
location =/firebase-messaging-sw.js {
root /home/ubuntu/yourpath/yourproject/FCM/;
}
更新自浅见处:
我已经阅读了很多关于 Service Workers 的文章,并且推进了我正在从事的项目,远远超过了我写这篇文章时的水平。
我在这里探索的主要问题(从域的根获得 firebase-messaging-sw.js
服务)已由下面的 ServiceWorkerView
解决。
有趣的事实:事实证明,firebase-messaging-sw.js
从域的根目录提供服务的原因是 Service Worker 的控制范围由 URL 定义。所以,同时:
http://whatever.com/firebase-messaging-sw.js
掌控一切,
http://whatever.com/static/firebase-messaging-sw.js
只能控制 /static/
下的所有内容(在这种情况下,只有 Django 提供的静态资源)。即使JS文件是静态的,它也需要控制该路径之外的页面。
A good starting point for learning about Service Workers
原题:
如何让 FCM service worker (firebase-messaging-sw.js
) 在 Django 中工作?
我正在使用 django
和 fcm-django
。
如何在根目录中提供 firebase-messaging-sw.js
?
Django 默认在路径“/static/”下提供静态资源。将 STATIC_URL 更改为“/”使 firebase-messaging-sw.js
可用,但没有其他任何东西..
我尝试了将以下内容放入我的 urls.py 中的建议:
url(r'^(?!/static/.*)(?P<path>.*\..*)$', RedirectView.as_view(url='/static/%(path)s'))
虽然显然是对正则表达式魔法的光荣使用,但事实证明服务工作者不能支持重定向。 (我想这也与有趣的事实有关)
我在 urlconf 中写了一个显式 URL 指向的视图。行得通。
class ServiceWorkerView(View):
def get(self, request, *args, **kwargs):
return render(request, 'fcmtest/firebase-messaging-sw.js')
urls.py:
path('firebase-messaging-sw.js', views.ServiceWorkerView.as_view(), name='service_worker')
现在 url http://localhost:8000/firebase-messaging-sw.js
服务于 javascript;然而,Firebase 抱怨内容类型是 text/plain
所以我将视图更改为:
class ServiceWorkerView(View):
def get(self, request, *args, **kwargs):
return render(request, 'fcmtest/firebase-messaging-sw.js', content_type="application/x-javascript")
我得到的错误是:
Uncaught (in promise) TypeError: Failed to register a ServiceWorker: A bad HTTP response code (404) was received when fetching the script.
我的firebase-messaging-sw.js
(注释none of the console.log statements print):
importScripts("https://www.gstatic.com/firebasejs/5.2.0/firebase-app.js");
importScripts("https://www.gstatic.com/firebasejs/5.2.0/firebase-messaging.js");
importScripts("https://www.gstatic.com/firebasejs/5.2.0/init.js");
// Initialize Firebase
var config = {
apiKey: "AIzaSyBOb5gh1Lry84116M1uvAS_xnKtcWUoNlA",
authDomain: "pyfcm-5f794.firebaseapp.com",
databaseURL: "https://pyfcm-5f794.firebaseio.com",
projectId: "pyfcm-5f794",
storageBucket: "pyfcm-5f794.appspot.com",
messagingSenderId: "813943398064"
};
console.log('in service worker - before initializeApp')
firebase.initializeApp(config);
console.log('in service worker - after initializeApp')
const messaging = firebase.messaging();
console.log('in service worker - after firebase.messaging')
// if the app is in the background (user not on page)
messaging.setBackgroundMessageHandler(function(payload) {
console.log('in service worker - in setBackgroundMessageHandler')
const title = "Hello World";
const options = {
body: payload.data.status
}
return self.registration.showNotification(title, options);
});
最后是我的设备注册页面(我不确定如何 运行 javascript 然后提交。form.submit() 没有用,但那可能是因为其他事情不起作用..?
(fcm/fcmtest/templates/fcmtest/device_registration.html
):
<head>
{% load static %}
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>FCM Device Registration</title>
<!-- update the version number as needed -->
<script src="https://www.gstatic.com/firebasejs/5.2.0/firebase.js"></script>
<script>
// Initialize Firebase
var config = {
apiKey: "AIzaSyBOb5gh1Lry84116M1uvAS_xnKtcWUoNlA",
authDomain: "pyfcm-5f794.firebaseapp.com",
databaseURL: "https://pyfcm-5f794.firebaseio.com",
projectId: "pyfcm-5f794",
storageBucket: "pyfcm-5f794.appspot.com",
messagingSenderId: "813943398064"
};
firebase.initializeApp(config);
</script>
<script defer src="https://www.gstatic.com/firebasejs/5.2.0/firebase-app.js"></script>
<!-- include only the Firebase features as you need -->
<script defer src="https://www.gstatic.com/firebasejs/5.2.0/firebase-auth.js"></script>
<!--<script defer src="https://www.gstatic.com/firebasejs/5.2.0/firebase-database.js"></script>-->
<script defer src="https://www.gstatic.com/firebasejs/5.2.0/firebase-messaging.js"></script>
<!--<script defer src="https://www.gstatic.com/firebasejs/5.2.0/firebase-storage.js"></script>-->
<!-- initialize the SDK after all desired features are loaded -->
<!--<script defer src="https://www.gstatic.com/firebasejs/5.2.0/init.js"></script>-->
</head>
<body>
<script>
function deviceRegistration() {
console.log('in deviceRegistration()')
firebase.initializeApp(config);
const messaging = firebase.messaging();
// public key generated in firebase console
messaging.usePublicVapidKey("BMEoHrnzLq5WNeyahbSxJNTyS-44bXug2wetxAWVMLMSUIQE0dexhP4pJhcSA-ZlQlneHURmYQcnq9ofym_sStY");
// console.log('{% static "firebase-messaging-sw.js" %}')
console.log("/firebase-messaging-sw.js")
// changed location passed to navigator.serviceWorker.register since I am no longer serving firebase-messaging.js from localhost/static/ (see that url hack)
// navigator.serviceWorker.register('{% static "firebase-messaging-sw.js" %}')
navigator.serviceWorker.register("/firebase-messaging-sw.js")
.then((registration) => {
console.log('before messaging.useServiceWorker')
messaging.useServiceWorker(registration);
console.log('after messaging.useServiceWorker')
// Request permission and get token.....
messaging.requestPermission()
.then(function(){
console.log("Have Permission");
})
.then(function(token) {
form = document.getElementById("registration_form");
registration_token = messaging.getToken();
form.registration_id = registration_token;
var isAndroid = navigator.userAgent.toLowerCase().indexOf("android") >= -1;
if (isAndroid) {
form.type = "android";
} else {
var isiOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
if (isiOS) {
form.type = "ios";
} else {
form.type = "web";
}
}
//form.submit();
})
.catch(function(err){
console.log("Permission denied");
})
});
// request permission to send notifications
messaging.requestPermission()
.then(function(){
console.log("Have Permission");
})
.then(function(token) {
form = document.getElementById("registration_form");
registration_token = messaging.getToken();
form.registration_id = registration_token;
var isAndroid = navigator.userAgent.toLowerCase().indexOf("android") >= -1;
if (isAndroid) {
form.type = "android";
} else {
var isiOS = /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
if (isiOS) {
form.type = "ios";
} else {
form.type = "web";
}
}
//form.submit();
})
.catch(function(err){
console.log("Permission denied");
})
// if user is on the page then show message directly instead of a notification
messaging.onMessage(function(payload) {
console.log('payload: ', payload);
});
}
</script>
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<form id="registration_form" method="post">{% csrf_token %}
<input id="name" type="text" />
<input id="type" type="hidden" />
<input id="user" type="hidden" value="{{ user.id }}" />
<input id="registration_id" type="hidden" />
<input id="btn_register" type="button" value="Register" onclick="deviceRegistration();" />
</form>
</body>
我尝试按照以下说明添加 manifest.json
https://firebase.google.com/docs/cloud-messaging/js/client
它目前由我的静态文件提供,并在注册和发送页面中链接
我的控制台中的错误:
Uncaught (in promise) TypeError: Failed to register a ServiceWorker: A bad HTTP response code (404) was received when fetching the script.
A bad HTTP response code (404) was received when fetching the script.
Failed to load resource: net::ERR_INVALID_RESPONSE
firebase-messaging-sw.js:3 Uncaught
(anonymous) @ firebase-messaging-sw.js:3
index.esm.js:1945 未捕获(承诺)
Object
browserErrorMessage:
"Failed to register a ServiceWorker: ServiceWorker script evaluation failed"
代码:
"messaging/failed-serviceworker-registration"
留言:
"Messaging: We are unable to register the default service worker. Failed to register a ServiceWorker: ServiceWorker script evaluation failed (messaging/failed-serviceworker-registration)."
堆栈:
"FirebaseError: Messaging: We are unable to register the default service worker. Failed to register a ServiceWorker: ServiceWorker script evaluation failed (messaging/failed-serviceworker-registration).↵ at https://www.gstatic.com/firebasejs/5.2.0/firebase-messaging.js:1:34104"
无法为 firebase-messaging-sw.js
提供服务的问题可以通过直接创建 ServiceWorkerView
到 GET
文件并硬编码 URLconf
.[=25 来解决=]
fcm/fcmtest/views.py:
class ServiceWorkerView(View):
def get(self, request, *args, **kwargs):
return render(request, 'fcmtest/firebase-messaging-sw.js', content_type="application/x-javascript")
fcm/fcmtest/urls.py
app_name = 'fcmtest'
urlpatterns = [
...
path('firebase-messaging-sw.js', views.ServiceWorkerView.as_view(), name='service_worker')
]
从域的根目录提供服务 firebase-messaging-sw.js
的原因是 Service Worker 的控制范围由 URL 路径定义。 Service Worker 可用路径下的所有内容都在其控制之下。
404
可能是由于 device_registration.html
中的 javascript 错误。 config
已被引用但尚未分配给。
function deviceRegistration() {
firebase.initializeApp(config);
此外,使用 Firebase 云消息传递没有必要(甚至可能有问题):
navigator.serviceWorker.register("/firebase-messaging-sw.js")
.then((registration) => {
messaging.useServiceWorker(registration);
})
而是使用 firebase.initializeApp(config);
在根目录下服务 manifest.json
可能是个好主意。
form.submit()
的问题在于,用于根据 promise 更改表单中的元素的代码不完整。调试后它会很好用。
我喜欢 Inversus 所做的事情,因为它会在 dev/test/prod 中发挥作用。也就是说,在生产中我选择让 nginx 为 firebase-messaging-sw.js 文件提供服务。 . .
# Firebase Cloud Messaging (FCM) requires this file to be served from
# your root directory
location =/firebase-messaging-sw.js {
root /home/ubuntu/yourpath/yourproject/FCM/;
}