So I have a site that is using Flask for the Front and Backend with Jinja templates. Currently testing with localhost (5000 is the backend and 8000 is for the frontend)
the page in question
main.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id='container'>
{% include "user.html" %}
</div>
</body>
</html>
user.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="user">
<h3>User: <span id="username"></span></h3>
<h4>Winnings: <span id="winnings"></span></h4>
<h4>Plays: <span id="credits"></span></h4>
</div>
<script>
var token = String(window.location).split('#')[1].split('&')[0].split('=')[1];
fetch('http://localhost:5000/user',{
method:'POST',
headers:{
'Authorization':'bearer '+token,
'Content-Type':'application/json',
'Access-Control-Allow-Origin':'*'
}
}).then(function(r){
return r.json();
}).then(function(response){
document.getElementById('username').innerHTML = response['username'];
document.getElementById('winnings').innerHTML = response['winnings'];
document.getElementById('credits').innerHTML = response['credits'];
}).catch(function(error){
console.log(error);
});
</script>
</body>
</html>
frontend.py
from flask import Flask, render_template, request, redirect, url_for, jsonify
from flask_cors import CORS
import requests
app = Flask(__name__)
cors = CORS(app)
#app.route('/main',methods=['GET'])
def main():
return render_template('main.html')
backend.py
from flask import Flask, send_file, abort, jsonify, request
from flask_cors import CORS
from functools import wraps
from urllib.request import urlopen
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import func, Column, Integer, String, create_engine
from flask_migrate import Migrate
from dotenv import load_dotenv
import pandas as pd
import os, sys, json, jwt, requests
load_dotenv()
app = Flask(__name__)
cors = CORS(app, origins=['http://localhost:8000'])
app.config.from_object('config')
db = SQLAlchemy(app)
migrate = Migrate(app,db,compare_type=True)
def requires_auth():
#auth code here to make sure the token in the header is valid
#token includes the user name, which is passed to the database
#app.route('/user',methods=['POST'])
#requires_auth()
def getUser (p):
try:
user = User.query.filter_by(username=p['user']).first()
return jsonify({
'success':True,
'username':username,
'credits':user.credit,
'winnings':user.score
})
except:
print(sys.exc_info())
abort(401)
When this runs, I get this in the browser, and the user information does not update:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:5000/user. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing). Status code: 200.
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:5000/user. (Reason: CORS request did not succeed). Status code: (null).
TypeError: NetworkError when attempting to fetch resource.
I checked the CORS, and the origin in the response matches the frontend port, as well as referer.
I expect the javascript in "user.html" to make the call to the backend. As it is part of "main.html" which is rendered when 'http:localhost:8000/main' is called.
enable Origin header and specify your server as origin. (don't use the default *)
fetch('http://localhost:5000/user', {
method:'POST',
headers:{
'Authorization':'bearer '+token,
'Content-Type':'application/json',
'Access-Control-Allow-Origin':'http://localhost:5000/user',
'Access-Control-Allow-Headers': ['Origin']',
}
})
looks like your using some custom auth decorator so you'll want to enable credentials
CORS(app, supports_credentials=True)
I got around the CORS issues by creating an endpoint on the frontend that forwards the request to the backend and returns a json object.
frontend.py
#app.route('/user',methods=['POST'])
def getUser():
r = requests.post(
'http://localhost:5000/user',
headers=request.headers,
)
return r.json()
user.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="user">
<h3>User: <span id="username"></span></h3>
<h4>Winnings: <span id="winnings"></span></h4>
<h4>Plays: <span id="credits"></span></h4>
</div>
<script>
var token = String(window.location).split('#')[1].split('&')[0].split('=')[1];
fetch('http://localhost:8000/user',{
method:'POST',
headers:{
'Authorization':'bearer '+token,
'Content-Type':'application/json',
'Access-Control-Allow-Origin':'http://localhost:8000/user',
'Access-Control-Allow-Headers': ['Origin']
}
}).then(function(r){
return r.json();
}).then(function(response){
document.getElementById('username').innerHTML = response['username'];
document.getElementById('winnings').innerHTML = response['winnings'];
document.getElementById('credits').innerHTML = response['credits'];
}).catch(function(error){
console.log(error);
});
</script>
</body>
</html>
Good tries all around.
Related
I want to make a chrome extension that will take url from browser and pass it to python script that in present in same folder, which will scrape the web page and output a JSON file with data.
Manifest.json
{
"name":"Scraper",
"version":"1.0.0",
"manifest_version":2,
"content_scripts":[
{
"matches":["https://www.amazon.in/*"],
"js":["content.js"]
}
],
"browser_action":{
"default_popup":"popup.html",
"default_title":"Scraper"
},
"permissions":["activeTab"],
"content_security_policy": "script-src 'self' https://ajax.googleapis.com; object-src 'self'"
}
popup.js
document.addEventListener('DOMContentLoaded',function(){
document.querySelector('button').addEventListener('click',onclick,false)
function onclick(){
chrome.tabs.query({currentWindow:true,active:true},
function(tabs){
var link = tabs[0].url;
chrome.tabs.sendMessage(tabs[0].id,link);
})
}
},false)
myscraper.py
from bs4 import BeautifulSoup as soup
import pandas as pd
import requests
import datetime
import json
current_time = datetime.datetime.now()
my_url = input()
#my_url = 'https://www.amazon.in/Dell-9570-15-6-inch-i7-8750H-Integrated/dp/B08C5DSRHM/ref=sr_1_1_sspa?crid=X09BHN0D2TJA&dchild=1&keywords=dell+xps+15&qid=1597921046&sprefix=dell+xps%2Caps%2C269&sr=8-1-spons&psc=1&spLa=ZW5jcnlwdGVkUXVhbGlmaWVyPUE1V09ZSFVKVk9aVEcmZW5jcnlwdGVkSWQ9QTAxODcyOTkxQVdJWkxDSFU2UjlZJmVuY3J5cHRlZEFkSWQ9QTA2NTg1NTUxUDJBME5HUE5HS1FaJndpZGdldE5hbWU9c3BfYXRmJmFjdGlvbj1jbGlja1JlZGlyZWN0JmRvTm90TG9nQ2xpY2s9dHJ1ZQ=='
header={
"User-Agent":'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36'
}
page = requests.get(my_url,headers = header)
page_soup = soup(page.content,'html.parser')
title = page_soup.find(id="productTitle").get_text()
price = page_soup.find(id="priceblock_ourprice").get_text()
available = page_soup.find(id="availability").get_text()
avail = available.split(".")
availability = avail[0]
dataPhone = {
'NAME':title.strip(),
'PRICE':price.strip(),
'AVAILABILITY':availability.strip(),
}
with open('amazon.json','w') as json_file:
json.dump(dataPhone,json_file)
content.js
chrome.runtime.onMessage.addListener(function(request){
alert(request)
$.ajax({
url: "./myscraper",
data: {param: link},
}).done(function() {
alert('finished python script');
});
console.log("Finished");
})
popup.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button>Run Python</button>
<script src="jquery-3.5.1.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="popup.js"></script>
<script src="content.js"></script>
</body>
</html>
Currently the code giving this error "ReferenceError: $ is not defined"
Can someone tell the problem or some other way to do it?
Double check that you have added the googleapis domain to your mainfest content_security_policy
"content_security_policy": "script-src 'self'
https://ajax.googleapis.com; object-src 'self'",
More discussed here
How to use jQuery in chrome extension?
The problem showing up when I click the button submit.The error coming out 404 not found and "Cannot POST/Index" in the website. Am I have logical problems on the code or problem that occur on the syntax. My program is doing without any http request, it's just a normal import express engine and integrate with html which I'm trying to do a basic post back function to express(server) and post the answer back to my angular html.
I'm trying to post the number back to the server for the calculation and doesn't know where is the error that make me could not doing Post Function. Please get the requirement file from me if the file that I uploaded is not completed.
app.component.html
In my HTML file do I need to add somethings for link the server.ts? Is there still any issue that I have to check on it?
<!doctype html>
<html lang="en">
<head>
<Title>Calculator</Title>
<meta charset="utf-8">
<title>Myapp</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" />
</head>
<body>
<h1 align="center">Angular Calculator</h1>
<div class="container">
<div class="card">
<div class="card-body">
<form action="index" method="POST">
<input type="number" name="num1" class="form-control" placeholder="Number">
<input type="number" name="num2" class="form-control" placeholder="Number">
<select ng-model="operator" name="operator">
<option>+</option>
<option>*</option>
<option>-</option>
<option>/</option>
</select>
<button type="submit">Submit</button>
</form>
<p>Calculation Of the number is :{{ result }} </p>
</div>
</div>
</div>
</body>
</html>
server.ts file
This is the by default server file that generate by npm which I'm not sure the syntax of code any problems for my first testing of addition functions.
import 'zone.js/dist/zone-node';
import 'reflect-metadata';
import * as bodyParser from 'body-parser';
import * as express from 'express';
import {join} from 'path';
// Express server
const app = express();
const PORT = process.env.PORT || 4000;
const DIST_FOLDER = join(process.cwd(), 'dist/browser');
// * NOTE :: leave this as require() since this file is built Dynamically from webpack
const {AppServerModuleNgFactory, LAZY_MODULE_MAP, ngExpressEngine, provideModuleMap} = require('./dist/server/main');
// Our Universal express-engine (found # https://github.com/angular/universal/tree/master/modules/express-engine)
app.engine('html', ngExpressEngine({
bootstrap: AppServerModuleNgFactory,
providers: [
provideModuleMap(LAZY_MODULE_MAP)
]
}));
app.set('view engine', 'html');
app.set('views', DIST_FOLDER);
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
// Example Express Rest API endpoints
// app.get('/api/**', (req, res) => { });
// Serve static files from /browser
app.get('*.*', express.static(DIST_FOLDER, {
maxAge: '1y'
}));
// All regular routes use the Universal engine
app.get('*', (req, res) => {
res.render('/app.component.html', { req });
});
app.get('*', (req, res) => {
res.status(404).send('data requests are not supported');
});
//have body-parser is a piece of express middleware that reads a form's
//input and stores it as a javascript object accessible through
//can not to include body-parser but not to get the raw request, your body and header are not in the root object of request parameter
app.post('/',(req, res) => {
//var num1 = req.body.operator
var result=req.body;
console.log(req.body);
var operator = req.body.operator
if (operator == "+")
{
res.render('/app.component.html', {
result: parseInt(req.body.num1) + parseInt(req.body.num2),
});
}
})
// Start up the Node server
app.listen(PORT, () => {
console.log(`Node Express server listening on http://localhost:${PORT}`);
});
The following line implies you are posting to /index:
<form action="index" method="POST">
For posting to your express service (which is hosted on port 4000 and hence the URL is http://localhost:4000), you have to define a submit behavior on your button. Check this for reference.
I think the problem is you don't include
'angular-route.js'
in your client-side code
you can't post to index <form action="index" method="POST">.
you need a server side file. like: <form action="form_process.php" method="POST">
Apologies if this question was answered, I tried searching but couldn't find what I'm looking for.
I want to build one .mjs file that has a library class code that I can use on both browser and Node.js. I don't want to use browsify or any 3rd party library. I want to use native JS Modules (.mjs). I'm willing to use Node 13.x so I completely replace my require statements with import and running experimental mode.
Here is an example, I want to use "node-fetch" for NodeJS and the native fetch API for the browser. So I called my variable "fetch". But I want to do an if statement so that if I'm running in the browser I can just use the native fetch, but If I'm in Node, I want to load the fetch api from node-fetch package.
fetch.mjs -shared code
//if node then do this.. else fetch will be defined in the browser
import fetch from "node-fetch"
export class AwesomeClass {
constructor(url)
{
this.url= url;
}
load () {
return fetch(this.url);
}
getAwesome() {}
}
index.mjs Node JS Client
import { AwesomeClass } from "./fetch.mjs"
const a = new AwesomeClass();
index.html browser Client
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script type = 'module'>
import { AwesomeClass } from "./fetch.mjs"
const a = new AwesomeClass();
</script>
</body>
</html>
Thanks to #Heretic Monkey for introducing me to dynamic import I was able to write a single .mjs file that works on both browser and node js. Here is the code for those interested.
It actually forced me to only load the fetch when I need it.
fetch.mjs library
export class AwesomeClass {
constructor(url)
{
this.url= url;
}
load () {
return import ("node-fetch").then(nodeFetch => nodeFetch.default(this.url)).catch(e=> fetch(this.url))
}
getAwesome() {}
}
index.mjs (node.js client)
import {AwesomeClass} from './fetch.mjs'
const ac = new AwesomeClass("https://api.github.com");
(async () => {
try{
const res = await ac.load();
console.log(await res.json());
}
catch(e)
{console.error(e)}
})()
index.html (browser)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<script type = 'module'>
import {AwesomeClass} from './fetch.mjs'
const ac = new AwesomeClass("https://api.github.com");
(async () => {
try{
const res = await ac.load();
console.log(await res.json());
}
catch(e)
{console.error(e)}
})()
</script>
</body>
</html>
I've launched a server with Express and attached MongoDB to it. And I put link to app.js file that is used in HTML webpage, but Idk why, but server wants to load js file from localhost:3000, but not from my folder. Here's my project folder:
app
|_node_modules
|_www
|_app.js
|_index.html
|_index.js
|_user.js
|_package.json
|_package-lock.json
app.js file is empty, but index.html isn't
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<script src="https://code.jquery.com/jquery-3.3.1.min.js" charset="utf-8"></script>
<script src="app.js" charset="utf-8"></script>
<meta charset="utf-8">
<style>
input {font-size: 30px}
</style>
<title></title>
</head>
<body>
<button onclick=hashGen()>GENERATE HASH</button>
<form action="/post" method="post">
<input type=text name=pass id=hash>
<input type=number name=pin>
<input type=submit value=submit />
</form>
</body>
</html>
And finally server script (index.js):
// Import modules
exp = require('express');
path = require('path');
parser = require('body-parser');
db = require('mongoose');
User = require('./user.js').User;
app = exp();
// Express & Mongoose params
app.listen(3000);
app.use(exp.static('public'));
app.use(parser.urlencoded({ extended: false }));
app.use(parser.json());
db.Promise = global.Promise;
db.connect("mongodb://localhost:27017/node-demo",{ useNewUrlParser: true });
// Load page
app.get('/',(req,res)=>{
res.sendFile(path.join(__dirname + '/www/main.html'));
})
// Take input & send to db
app.post('/post',(req,res)=>{
let data = new User(req.body);
data.save().then(item =>{
res.send(req.body.user + ' added.')
}).catch(err => {
res.status(400).send("unable to save to database");
});
})
Then I launched my server with nodemon index and it loaded, but with two errors:
GET http://localhost:3000/app.js 404 (Not Found)
localhost/:1 Refused to execute script from 'http://localhost:3000/app.js' because its MIME type ('text/html') is not executable, and strict MIME type checking is enabled.
Do u guys know what's wrong?
You mapped wrong root directory for your public/static files:
app.use(exp.static('public'));
Should be:
app.use(exp.static('www'));
Update from a place of mild understanding:
I have read much about Service Workers and advanced the project I'm working on far past where it was when I wrote this.
The main issue I was exploring here (getting firebase-messaging-sw.js served from the root of the domain) was solved by the ServiceWorkerView below.
Fun fact: turns out that the reason to have firebase-messaging-sw.js served from the root of the domain is that the scope of a Service Worker's control is defined by the URL. So, while:
http://whatever.com/firebase-messaging-sw.js has control over everything,
http://whatever.com/static/firebase-messaging-sw.js only has control over everything under /static/ (in this case, only the static resources served by Django). Even though the JS file is static, it needs to control pages outside that path.
A good starting point for learning about Service Workers
Original Question:
How do I get the FCM service worker (firebase-messaging-sw.js) to work in Django?
I'm using django with fcm-django.
How do I serve firebase-messaging-sw.js at the root?
Django serves static assets by default under the path “/static/“. Changing the STATIC_URL to “/“ makes firebase-messaging-sw.js available but nothing else is..
I tried a suggestion to put the following in my urls.py:
url(r'^(?!/static/.*)(?P<path>.*\..*)$', RedirectView.as_view(url='/static/%(path)s'))
While clearly a glorious use of regex magic, it turns out that the service worker can't be behind a redirect. (I guess this also has to do with the fun fact)
I wrote a view pointed to by an explicit URL in the urlconf. that works.
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')
Now the url http://localhost:8000/firebase-messaging-sw.js serves up the javascript; however, Firebase complains that the content-type is text/plain
So I changed the view to:
class ServiceWorkerView(View):
def get(self, request, *args, **kwargs):
return render(request, 'fcmtest/firebase-messaging-sw.js', content_type="application/x-javascript")
And the error I get is:
Uncaught (in promise) TypeError: Failed to register a ServiceWorker: A
bad HTTP response code (404) was received when fetching the script.
My firebase-messaging-sw.js (note 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);
});
and finally, my device registration page (I'm not sure how to run the javascript and then submit. form.submit() didn't work but that might be because of other things not working..?
(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>
I tried adding a manifest.json as per instructions on
https://firebase.google.com/docs/cloud-messaging/js/client
It is currently served from my static files and is linked in the registration and send pages
The errors in my console:
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 Uncaught (in promise)
Object
browserErrorMessage:
"Failed to register a ServiceWorker: ServiceWorker script evaluation failed"
code:
"messaging/failed-serviceworker-registration"
message:
"Messaging: We are unable to register the default service worker. Failed to register a ServiceWorker: ServiceWorker script evaluation failed (messaging/failed-serviceworker-registration)."
stack:
"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"
The issue of not being able to serve firebase-messaging-sw.js can be solved by creating a ServiceWorkerView to GET the file directly and hardcoding the URLconf.
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')
]
The reason to serve firebase-messaging-sw.js from the root of the domain is that the scope of a Service Worker's control is defined by the URL path. Everything under the path the Service Worker is available at is under its control.
The 404 might be due to a javascript error in device_registration.html. config is referenced but has not been assigned to.
function deviceRegistration() {
firebase.initializeApp(config);
Also, it is not necessary (maybe even problematic) to do this with Firebase Cloud Messaging:
navigator.serviceWorker.register("/firebase-messaging-sw.js")
.then((registration) => {
messaging.useServiceWorker(registration);
})
Instead, use firebase.initializeApp(config);
It might be a good idea to serve manifest.json at the root.
The issue with form.submit() is that the code to alter the elements in the form from the promise is incomplete. After debugging that it will work great.
I like what Inversus has done because it will work in dev/test/prod. That being said, in production I have elected to let nginx serve the firebase-messaging-sw.js file . . .
# 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/;
}