从 Sencha Touch 2 跨域更新到外部服务器
Posted
技术标签:
【中文标题】从 Sencha Touch 2 跨域更新到外部服务器【英文标题】:Cross-domain Update from Sencha Touch 2 to external server 【发布时间】:2012-09-15 01:35:57 【问题描述】:尝试创建一个 Sencha-Touch-2 应用程序同步到 Node.js 服务器;下面的代码。 服务器使用同一 IP 上的另一个端口,因此这是跨域的。 (服务器使用 Mongoose 与 MongoDB 后端通信(未显示))
使用如图所示的 JSONP 代理可以从服务器读取数据,但在写入时会中断: “JSONP 代理只能用于读取数据”。 我猜 JSONP Proxy writer 配置只是用来写查询而不是用来写同步(保存)。
Sencha 文档声明 Ajax 代理不能跨域,即使
跨域Ext.Ajax/Ext.data.Connection
在 Sencha 论坛中讨论:
http://www.sencha.com/forum/showthread.php?17691-Cross-domain-Ext.Ajax-Ext.data.Connection
我找到了几种方法来进行(跨域)JSON 帖子(例如 Mobile Application Using Sencha Touch - JSON Request Generates Syntax Error) 但不知道如何将其作为作家集成到同步我的商店的代理中。 Sencha Touch: ScriptTagProxy url for create/update functionality 似乎提供了指针,但这是 ajax,显然不适合跨域。
我已经阅读这个论坛和其他地方几天了,但我似乎被困住了。任何帮助将不胜感激。
Node.js 和 Restify 服务器
var server = restify.createServer(
name: 'Server',
key: fs.readFileSync(root+'/'+'privatekey.pem'),
certificate: fs.readFileSync(root+'/'+'certificate.pem')
);
server.use(restify.bodyParser());
server.use(restify.queryParser());
function getMessages(req, res, next)
Model.find(function (err,data)
res.setHeader('Content-Type', 'text/javascript;charset=UTF-8');
res.send(req.query["callback"] + '("records":' + JSON.stringify(data) + ');');
);
function postMessage(req, res, next) //not yet tested
var obj = new Model();
obj.name = req.params.name;
obj.description = req.params.description;
obj.date = new Date();
obj.save(function (err)
if (err) throw err;
console.log('Saved.');
res.send('Saved.');
);
server.post(/^\/atapp/, postMessage);
server.get(/^\/atapp/, getMessages);
server.listen(port, ipaddr, function()
console.log('%s: secure Node server started on %s:%d ...', Date(Date.now()), ipaddr, port);
);
煎茶触摸 2
型号
Ext.define('ATApp.model.User',
extend: 'Ext.data.Model',
config:
fields: [
name: 'name', type: 'string' ,
name: 'description', type: 'string' ,
name: 'date', type: 'date' ,
name: '_id'
...
商店
Ext.define('ATApp.store.Data',
extend: 'Ext.data.Store',
requires: [
'ATApp.model.User',
'Ext.data.proxy.JsonP'
],
config:
autoLoad: true,
model: 'ATApp.model.User',
storeId: 'Data',
proxy:
type: 'jsonp',
model: 'ATApp.model.User',
url: 'https://192.168.2.45:13017/atapp',
reader:
type: 'json',
idProperty: '_id',
rootProperty: 'records',
useSimpleAccessors: true
,
writer:
type: 'json',
allowSingle: false,
encode: true,
idProperty: '_id',
rootProperty: 'records'
...
控制器
onNewDataRecord: function (view)
console.log('newDataRecord');
var now = new Date();
var record = Ext.create('ATApp.model.User',
date: now,
name: '..',
description: '..'
);
var store = Ext.data.StoreManager.lookup('Data')
record.setProxy(store.getProxy());
store.add(record);
this.activateEditor(record);
,
...
【问题讨论】:
【参考方案1】:在 Sencha-Touch-2 应用程序中,浏览器禁止跨域 AJAX 调用(这违反了同源安全策略)。这与不同的域、不同的 IP 地址甚至同一 IP 地址上的不同端口有关。 JSONP 通过在新启动的 HTTP GET 消息中获取/读取封装在脚本标记中的数据来部分规避这一点。通过这种方式,Sencha-Touch-2 JSONP 代理可以从(跨域)服务器加载存储(获取/读取)。但是,JSONP 代理无法写入数据。在1 和2 中描述了一种我已经适应的方法。
我的解决方案使用 JSONP 代理来获取数据,但不存储(它不能)。相反,新记录以及要保存或删除的记录在新启动的 HTTP GET 消息中与服务器通信。即使只使用 HTTP GET,服务器也会接受消息 get
(在上面的问题中描述)、put
、del
和 new
。 Get
由 JSONP 存储/代理 load()
使用。
Node.js 服务器
//routes
server.get(/^\/atapp\/put/, putMessage);
server.get(/^\/atapp\/get/, getMessages);
server.get(/^\/atapp\/del/, delMessage);
server.get(/^\/atapp\/new/, newMessage);
function newMessage(req, res, next)
var obj = new Model(); // Mongoose create new MongoDB object
obj.save(function (err,data)
var x = err || data;
res.setHeader('Content-Type', 'text/javascript;charset=UTF-8');
res.send(req.query["callback"] + '("payload":' + JSON.stringify(x) + ');');
); // send reply to Sencha-Touch 2 callback
function putMessage(req, res, next)
var q = JSON.parse(req.query.data); // no reply: add error recovery separately
var obj = Model.findByIdAndUpdate(q.key,q.val);
function delMessage(req, res, next)
var key = JSON.parse(req.query.data);
Model.findByIdAndRemove(key); // no reply: add error recovery separately
煎茶控制器
新
onNewDataRecord: function (view)
var control = this;
Ext.Ajax.Crossdomain.request(
url: 'https://192.168.2.45:13017/atapp/new',
rootProperty: 'payload',
scriptTag: true, // see [1](http://code.google.com/p/extjsdyntran/source/browse/trunk/extjsdyntran/WebContent/js/3rdparty/Ext.lib.Ajax.js?r=203)
success: function(r) // process synchronously after response
var obj = r.payload;
var store = Ext.data.StoreManager.lookup('Data');
var key = obj._id // MongoDB document id
store.load(function(records, operation, success) // add new record to store
var ind = store.findBy(function(rec,id)
return rec.raw._id==key;
); // identify record in store
var record = store.getAt(ind);
control.onEditDataRecord(view,record);
, this);
);
保存
onSaveDataRecord: function (view, record)
rec = key:record.data.id, val: // save template
var i; for (i in record.modified) rec.val[i]=record.data[i];
var delta = Ext.encode(rec); // only save modified fields
Ext.Ajax.Crossdomain.request(
url: 'https://192.168.2.45:13017/atapp/put',
params:
data: delta,
,
rootProperty: 'payload',
scriptTag: true, // Use script tag transport
);
,
删除
onDelDataRecord: function (view, record)
var key = record.data.id;
Ext.Ajax.Crossdomain.request( // delete document in db
url: 'https://192.168.2.45:13017/atapp/del',
params:
data: Ext.encode(key),
format: 'json'
,
rootProperty: 'payload',
scriptTag: true, // Use script tag transport
);
record.destroy(); // delete record from store
,
【讨论】:
以上是关于从 Sencha Touch 2 跨域更新到外部服务器的主要内容,如果未能解决你的问题,请参考以下文章
Sencha Touch 2 & Spring Security 跨域登录
如何从外部控制器函数调用控制器函数,如 sencha touch 中的全局函数