XHR 和 baidubce-sdk

Content-Type

在开发 baidubce-sdk 的时候,遇到了在不同浏览器(主要是 Firefox 和 Chrome)下调用 xhr.setRequestHeader 设置 Request Header 之后,内部的处理逻辑有一些细微的差别,导致baidubce-sdk无法正常的工作。

1
2
3
4
5
var xhr = new XMLHttpRequest();
xhr.setRequestHeader('Content-Type', 'foo/bar');
// 当Method !== 'GET' 的时候
xhr.open('POST', '', true);
xhr.send('');

对于上面这段儿代码,因为我们显式的设置了Content-Type,所以我们期望的是服务器收到的 Request HeaderContent-Type 应该是 foo/bar,实际上在 Firefox 里面会自动添加 charset=UTF-8,也就是服务器得到的信息是 foo/bar; charset=UTF-8

因为根据 ak 和 sk 计算签名的时候,Content-Type作为其中的一个因子参与计算的。Firefox下面的这个问题,导致 client 和 server 计算出来的签名不一致,所以 server 就拒绝了某些请求。

Content-Length

第二个兼容性的问题是关于Content-Length的,因为 baidubce-sdk 最初的是为 Node.js 开发的,通过 browserify 处理之后直接运行在浏览器里面。

Node.js里面,我们直接使用的require('http')模块,可以任意设置Request Header里面的字段,但是在XMLHttpRequest的文档里面,限制了一些可以设置的Header

GET请求里面,Content-Length值是0,此时 client 是有这个信息的,因此会把Content-Length作为计算签名的一个因子,不过因为xhr的限制,我们无法设置这个 Header,因此 server 收到的 GET 请求里面,Request Header 里面是没有这个Content-Length的,这也就导致了签名计算不一致的问题。

baidubce-sdk

问题都描述清楚了,对应的解决方案也就有了:

  1. POST的时候给所有浏览器下面都加上; charset=UTF-8这部分信息
  2. 使用 sendAsBinary 代替 send,不过 browserify 生成的代码里面没有调用这个 API,需要自己去修改一下才可以。
  3. 调用xhr.send参数的时候,不要传递string,改成Uint8Array,也可以避免这个问题。

广告贴来了

baidubce-sdk封装了百度开放云提供的一些基础API,比如云存储(BOS),音视频转码(Media),欢迎有这方面需求的童鞋试用。

1
npm i baidubce-sdk

参考

知识共享许可协议