我试图将sql.js
(基于JS的SQLite https://github.com/kripken/sql.js/)集成到我的Chrome应用中,但在我启动应用时,控制台显示以下错误:
Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "default-src 'self' chrome-extension-resource:". Note that 'script-src' was not explicitly set, so 'default-src' is used as a fallback.
Uncaught EvalError: Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "default-src 'self' chrome-extension-resource:".
我的清单文件如下:
{
"manifest_version": 2,
"name": "Chrome App",
"description": "This is the test app!!!",
"version": "1",
"icons": {
"128": "icon_128.png"
},
"permissions": ["storage"],
"app": {
"background": {
"scripts": ["background.js"]
},
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'"
},
"minimum_chrome_version": "28"
}
答案 0 :(得分:3)
@MarcRochkind我想在您的图书中添加一些知识,以便在Chrome应用中集成SQL.js。
很有可能只需很少的努力(考虑到政策和规则的服从)。
为了集成使用eval
的任何内容,您需要对脚本的特定部分进行沙箱化。对于SQL.js,它是整个库。
这可以通过iframe来完成,该iframe需要在主要.html
文档中设置,该文档被调用以创建(或主要)窗口,例如chrome.app.window.create('index-app.html', { ..
主文档和iframe之间的通信基础是使用postMessage来发送和接收消息。
假设此iframe的来源称为/iframes/sqljs-sandboxed.html
。
在manifest.json
中,您需要将sqljs-sandboxed.html
指定为沙箱。指定的沙箱可以运行eval
和eval
- 类似new Function
等构造。
{
"manifest_version": 1,
"name": "SQL.js Test",
..
"sandbox": {
"pages": [
"iframes/sqljs-sandboxed.html",
]
}
}
sqljs-sandboxed.html
使用事件侦听器对message
类型的事件做出反应。在这里,您可以简单地添加逻辑(为简单起见,我使用了switch语句)来执行使用SQL.js构建的任何内容。
以sqljs-sandboxed.html
的内容为例:
<script src="/vendor/kripken/sql.js"></script>
<script>
(function(window, undefined) {
// a test database
var db = new SQL.Database();
// create a table with some test values
sqlstr = "CREATE TABLE hello (a int, b char);";
sqlstr += "INSERT INTO hello VALUES (0, 'hello');";
sqlstr += "INSERT INTO hello VALUES (1, 'world');";
// run the query without returning anything
db.run(sqlstr);
// our event listener for message
window.addEventListener('message', function(event) {
var params = event.data.params,
data = event.data.data,
context = {};
try {
switch(params.cmd) {
case '/do/hello':
// process anything with sql.js
var result = db.exec("SELECT * FROM hello");
// set the response context
context = {
message: '/do/hello',
hash: params.hash,
response: result
};
// send a response to the source (parent document)
event.source.postMessage(context, event.origin);
// for simplicity, resend a response to see if event in
// 'index-app.html' gets triggered a second time (which it
// shouldn't)
setTimeout(function() {
event.source.postMessage(context, event.origin);
}, '1000');
break;
}
} catch(err) {
console.log(err);
}
});
})(window);
</script>
仅创建一次测试数据库,并且事件侦听器使用简单的开关镜像API。这意味着为了使用SQL.js,您需要针对API进行编写。乍一看,这可能有点令人不舒服,但从简单的意义上讲,这个想法在实现REST服务时是相同的,在我看来,从长远来看,这是非常舒服的。
为了发送请求,index-app.html
是发起者。重要的是要指出可以异步地对iframe 进行多次请求。为了防止交叉传输,每个请求都以唯一标识符的形式发送状态参数(在我的示例中为unique-ish)。同时,监听器附加在message
事件上,该事件过滤掉所需的响应并触发其指定的回调,如果触发,则将其从事件堆栈中删除。
对于快速演示,会创建一个自动对message
事件进行附加和分离的对象。最终,listen
函数最终应该过滤特定的字符串值,例如sandbox === 'sql.js'
(在此示例中未实现),以便加快使用沙箱化的多个iframe时可能发生的许多message
事件的过滤器选择(例如,用于模板的handlebars.js)。< / p>
var sqlRequest = function(request, data, callback) {
// generate unique message id
var hash = Math.random().toString(36).substr(2),
// you can id the iframe as wished
content_window = document.getElementById('sqljs-sandbox').contentWindow,
listen = function(event) {
// attach data to the callback to be used later
this.data = event.data;
// filter the correct response
if(hash === this.data.hash) {
// remove listener
window.removeEventListener('message', listen, false);
// execute callback
callback.call(this);
}
};
// add listener
window.addEventListener('message', listen, false);
// post a request to the sqljs iframe
content_window.postMessage({
params: {
cmd: request,
hash: hash
},
data: data
}, '*');
};
// wait for readiness to catch the iframes element
document.addEventListener('DOMContentLoaded', function() {
// faking sqljs-sandboxed.html to be ready with a timeout
setTimeout(function() {
new sqlRequest('/do/hello', {
allthedata: 'you need to pass'
}, function() {
console.log('response from sql.js');
console.log(this.data);
});
}, '1000');
});
为简单起见,我使用超时来阻止在加载iframe之前发送请求。根据我的经验,最佳做法是让iframe向其父文档发送一条消息,说明iframe已加载,从此处开始使用SQL.js。
最后,在index-app.html
中指定iframe
<iframe src="/iframes/sqljs-sandboxed.html" id="sqljs-sandbox"></iframe>
index-app.html
的内容可能是
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
</head>
<body>
<iframe src="/iframes/sqljs-sandboxed.html" id="sqljs-sandbox"></iframe>
<h1>Hello, let's code with SQL.js!</h1>
<script src="/assets/js/sqljs-request.js"></script>
</body>
</html>
答案 1 :(得分:1)
“content_security_policy”不是Chrome应用程序的文档清单属性。
据我所知,sql.js与Chrome应用程序不兼容,正如您的错误消息所示。
SQLite的一种变体,即Web SQL,具体记录为与Chrome应用无关。
IndexedDB可与Chrome应用程序配合使用,但(a)它不是基于SQL的,并且(b)它的实用性有限,因为它是沙盒,而其他应用程序甚至连其他Chrome应用程序都看不到数据。< / p>
您对“Chrome打包应用程序”的引用可能意味着您正在考虑使用旧版“打包应用程序”,这些应用程序的操作规则与新版Chrome应用程序不同。但是,Google不再支持打包的应用,也不应该开发。也许您正在查看软件包应用程序的文档或示例,而不是Chrome应用程序。