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

时间:2013-07-30 00:07:01

标签: jquery json node.js xmlhttprequest cors

我们发现Gingerbread默认浏览器处理跨域请求的方式与大多数其他浏览器不同。服务器代码适当地响应OPTIONS呼叫,所有正确的标头访问控制标头和200状态代码,并以POST状态响应200呼叫代码和适当的身体。服务器是用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);

当Gingerbread浏览器向/ route发出CORS请求时,它收到了responseText "OK{some:'json object'}"。由于我们使用的是jQuery,并且因为Content-Type响应头是application/json,因为json响应体不可解析,jQuery失败了。我们测试的每个其他浏览器都使用"{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,所以我们仍然遇到错误。

这里发生了什么?

1 个答案:

答案 0 :(得分:1)

事实证明,Gingerbread - 至少我们使用的版本 - 会自动连接OPTIONS请求和POST请求的响应。此外,Express会自动发送"OK"正文,以便在没有特定正文且状态代码为200的情况下进行回复。

上面的例子令人痛苦地显而易见,但我们并没有将其缩小到那个程度。因此,我们追逐已知工作版本和失败版本之间标题之类的微小差异。