我有一个使用AngularJS编写的单页Web应用程序。它使用PouchDB复制到CouchDB服务器,并且工作正常。
当我尝试通过添加cache.manifest将网页转换为脱机使用时出现问题。突然,无论是脱机工作还是联机工作,所有复制任务都会引发错误并停止工作。
在Chrome中,它只是说“ GET … myCouchIP / myDB /?_ nonce = CxVFIwnEJeGFcyoJ net :: ERR_FAILED”
在Firefox中,它还会引发错误,但会提到请求已被阻止-尝试启用CORS。
根据PouchDB设置页面上的说明,在远程CouchDB上启用了CORS。另外,它在不使用cache.manifest的情况下也可以正常工作(即,它对我的办公桌,服务器和VM之间的所有不同IP地址都非常满意- 它是一个原型,因此目前没有域名)。
顺便说一句,目前我不使用任何身份验证。管理员方有效。
那么添加cache.manifest时会发生什么变化?线索感激不尽。提前致谢。
app.js
var app = angular.module('Assets', ['assets.controllers', 'ngRoute']); app.config(['$routeProvider', function($routeProvider) { $routeProvider. when('/', { controller: 'OverviewCtrl', templateUrl: 'views/overview.html' }). when('/new', { controller: 'NewMachineCtrl', templateUrl: 'views/machineForm.html' }). otherwise({redirectTo: '/'}); }]);
controller.js
var _control = angular.module('assets.controllers', ['assets.services']); _control.controller('OverviewCtrl', ['$scope', 'Machine', function($scope, Machine) { var promise = Machine.getAll(); promise.then(function(machineList) { $scope.machines = machineList; }, function(reason) { alert('Machine list is empty: ' + reason); }); }]); _control.controller('UpdateMachineCtrl', ['$scope', '$routeParams', 'Machine', function($scope, $routeParams, Machine) { $scope.title = "Update Installation Details"; var promise = Machine.getSingle($routeParams.docId); promise.then(function(machine) { $scope.machine = machine; }, function(reason) { alert('Record could not be retrieved'); }); $scope.save = function() { Machine.update($scope.machine); }; }]); _control.controller('SyncCtrl', ['$scope', 'Machine', function($scope, Machine) { $scope.syncDb = function() { Machine.sync(); Machine.checkConflicts(); }; $scope.checkCors = function() { // Check CORS is supported var corsCheck = function(method, url) { var xhr = new XMLHttpRequest(); if ("withCredentials" in xhr) { // XHR for Chrome/Firefox/Opera/Safari. xhr.open(method, url, true); } else if (typeof XDomainRequest != "undefined") { // XDomainRequest for IE. xhr = new XDomainRequest(); xhr.open(method, url); } else { // CORS not supported. console.log('CORS not supported by browser'); } xhr.onload = function() { console.log('Response from CORS ' + method + ' request to ' + url + ': ' + xhr.responseText); }; xhr.onerror = function() { console.log('Error response from CORS ' + method + ' request to ' + url + ': ' + xhr.responseText); }; xhr.send(); }; var server = 'http://10.100.3.21:5984/ass_support'; corsCheck('GET', server); corsCheck('PUT', server); corsCheck('POST', server); corsCheck('HEAD', server); // corsCheck('DELETE', server); }; }]);
service.js
var _service = angular.module('assets.services', []); _service.constant('dbConfig',{ dbName: 'assets', dbServer: 'http://myCouchServerIp:5984/' }); /** * Make PouchDB available in AngularJS. */ _service.factory('$db', ['dbConfig', function(dbConfig) { PouchDB.enableAllDbs = true; var localDb = new PouchDB(dbConfig.dbName); var remoteDb = dbConfig.dbServer + dbConfig.dbName; var options = {live: true}; var syncError = function() { console.log('Problem encountered during database synchronisation'); }; console.log('Replicating from local to server'); localDb.replicate.to(remoteDb, options, syncError); console.log('Replicating from server back to local'); localDb.replicate.from(remoteDb, options, syncError); return localDb; }]); _service.factory('Machine', ['$q', '$db', '$rootScope', 'dbConfig', function($q, $db, $rootScope, dbConfig) { return { update: function(machine) { var delay = $q.defer(); var doc = { _id: machine._id, _rev: machine._rev, type: machine.type, customer: machine.customer, factory: machine.factory, lineId: machine.lineId, plcVersion: machine.plcVersion, dateCreated: machine.dateCreated, lastUpdated: new Date().toUTCString() }; $db.put(doc, function(error, response) { $rootScope.$apply(function() { if (error) { console.log('Update failed: '); console.log(error); delay.reject(error); } else { console.log('Update succeeded: '); console.log(response); delay.resolve(response); } }); }); return delay.promise; }, getAll: function() { var delay = $q.defer(); var map = function(doc) { if (doc.type === 'machine') { emit([doc.customer, doc.factory], { _id: doc._id, customer: doc.customer, factory: doc.factory, lineId: doc.lineId, plcVersion: doc.plcVersion, } ); } }; $db.query({map: map}, function(error, response) { $rootScope.$apply(function() { if (error) { delay.reject(error); } else { console.log('Query retrieved ' + response.rows.length + ' rows'); var queryResults = []; // Create an array from the response response.rows.forEach(function(row) { queryResults.push(row.value); }); delay.resolve(queryResults); } }); }); return delay.promise; }, sync: function() { var remoteDb = dbConfig.dbServer + dbConfig.dbName; var options = {live: true}; var syncError = function(error, changes) { console.log('Problem encountered during database synchronisation'); console.log(error); console.log(changes); }; var syncSuccess = function(error, changes) { console.log('Sync success'); console.log(error); console.log(changes); }; console.log('Replicating from local to server'); $db.replicate.to(remoteDb, options, syncError). on('error', syncError). on('complete', syncSuccess); console.log('Replicating from server back to local'); $db.replicate.from(remoteDb, options, syncError); } }; }]); _service.factory('dbListener', ['$rootScope', '$db', function($rootScope, $db) { console.log('Registering a onChange listener'); $db.info(function(error, response) { $db.changes({ since: response.update_seq, live: true, }).on('change', function() { console.log('Change detected by the dbListener'); // TODO work out why this never happens }); }); }]);
cache.manifest
CACHE MANIFEST # views views/machineForm.html views/overview.html # scripts scripts/vendor/pouchdb-2.2.0.min.js scripts/vendor/angular-1.2.16.min.js scripts/vendor/angular-route-1.2.16.min.js scripts/app.js scripts/controllers/controller.js scripts/services/service.js
index.html
<!DOCTYPE html> <html lang="en" manifest="cache.manifest" data-ng-app="Assets"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Asset Management</title> <script src="scripts/vendor/angular-1.2.16.min.js" type="text/javascript"></script> <script src="scripts/vendor/angular-route-1.2.16.min.js" type="text/javascript></script> <script src="scripts/vendor/pouchdb-2.2.0.min.js" type="text/javascript"></script> <script src="scripts/app.js" type="text/javascript"></script> <script src="scripts/services/service.js" type="text/javascript"></script> <script src="scripts/controllers/controller.js" type="text/javascript"></script> </head> <body> <div id="content"> <nav class="sidebar"> <h3>Options</h3> <div> <a class="active" data-ng-href="#/">Overview</a> <a data-ng-href="#" data-ng-controller="SyncCtrl" data-ng-click="syncDb()">Synchronise</a> <a data-ng-href="" data-ng-controller="SyncCtrl" data-ng-click="checkCors()">Check CORS</a> </div> </nav> <section class="main"> <div data-ng-view></div> </section> </div> </body> </html>
overview.html
<h3>Installation Overview</h3> <table> <tr> <th>Customer</th> <th>Factory</th> <th>Line Id</th> <th>PLC Version</th> </tr> <tr data-ng-repeat="machine in machines"> <td>{{machine.customer}}</td> <td>{{machine.factory}}</td> <td><a data-ng-href="#/view/{{machine._id}}">{{machine.lineId}}</a></td> <td>{{machine.plcVersion}}</td> </tr> </table>
machineForm.html
<h3>{{title}}</h3> <form name="machineForm" data-ng-submit="save()"> <div> <label for="customer">Customer:</label> <div><input data-ng-model="machine.customer" id="customer" required></div> </div> <div> <label for="factory">Factory:</label> <div><input data-ng-model="machine.factory" id="factory" required></div> </div> <div> <label for="lineId">Line ID:</label> <div><input data-ng-model="machine.lineId" id="lineId" required></div> </div> <div> <label for="plcVersion">PLC Version:</label> <div><input data-ng-model="machine.plcVersion" id="plcVersion"></div> </div> <div><button data-ng-disabled="machineForm.$invalid">Save</button></div> </form>
尝试将您的cache.manifest文件更改为此:
CACHE MANIFEST CACHE: # views views/machineForm.html views/overview.html # scripts scripts/vendor/pouchdb-2.2.0.min.js scripts/vendor/angular-1.2.16.min.js scripts/vendor/angular-route-1.2.16.min.js scripts/app.js scripts/controllers/controller.js scripts/services/service.js NETWORK: *
使用清单文件时,即使您处于联机状态, 所有 非缓存资源也会在缓存页面上失败。NETWORK部分告诉浏览器允许对非缓存资源的请求(当然,它们在脱机时仍然会失败)。