我们发现Gingerbread默认浏览器处理跨域请求的方式与大多数其他浏览器不同。服务器代码使用所有正确的头访问控制头和200
状态代码适当地响应OPTIONS
调用,并使用200
状态代码和适当的主体来响应POST
调用。服务器是在Node中编写的,使用Express,对于本测试而言,它非常简单:
var express = require('express');
var http = require('http');
var app = express();
var server = http.createServer(app);
// middleware
app.use(express.logger('dev'));
app.use(function(req, res, next) {
var origin = req.get('origin');
if (origin) {
res.header({
'Access-Control-Allow-Origin': origin,
'Access-Control-Allow-Methods': 'GET,POST,OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type',
'Access-Control-Allow-Credentials': true
});
}
if (req.method === "OPTIONS")
return res.send(200);
if (req.method !== "GET" && req.method !== "POST")
return res.send(405);
next();
});
app.use(express.json());
app.use(app.router);
app.post('/the/route', function(req, res) {
res.json(200, {some: 'json object'});
});
server.listen(process.env.PORT || 3000);
当姜饼浏览器向/te/route发出CORS请求时,它收到了"OK{some:'json object'}"
的responseText
。由于我们使用的是jQuery,并且Content-Type
响应头是application/json
,所以jQuery由于json响应体不可解析而导致请求失败。我们测试过的其他所有浏览器都使用"{some:'json object'}"
进行响应,并按预期进行解析。
那么"OK"是从哪里来的呢?
我们进一步简化了服务器,忽略了整个app.router
。也许这就是问题所在。
...
// middleware
app.use(express.logger('dev'));
app.use(function(req, res, next) {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET,POST,OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type');
res.header('Access-Control-Allow-Credentials', true);
res.json(200, {some: 'json object'});
});
这一次,令我们惊讶的是,服务器在Gingerbread浏览器上的响应是"{some:'json object'}{some:'json object'}"
,在其他所有浏览器上都是"{some:'json object}"
。当然,前者仍然不是有效的json,所以我们仍然遇到了一个错误。
这是怎么回事?
事实证明,Gingerbread——至少是我们使用的版本——自动连接了OPTIONS
请求和POST
请求的响应。此外,Express在没有特定主体和状态代码200
的情况下,自动发送一个"OK"
主体作为响应。
上面的例子让这一点非常明显,但我们并没有把它缩小到那个程度。因此,我们一直在寻找已知工作版本和失败版本之间在标头等方面的最小差异。