姜饼浏览器跨域响应连接错误



我们发现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"主体作为响应。

上面的例子让这一点非常明显,但我们并没有把它缩小到那个程度。因此,我们一直在寻找已知工作版本和失败版本之间在标头等方面的最小差异。

最新更新