时间:2018年11月14日
这是在和媒体对接时遇到的一个问题,不得不说有的媒体是真的变态。
一般情况下媒体对接是比较简单的,就是把我们本地的数据发送给媒体,之后媒体给我们反馈,生成一个m_id
,我们拿到这个m_id
之后会存在数据库里,这就完成了媒体对接的一半。之后我们通过m_id
来查询发送的数据是否通过审核,这也就完成了媒体对接了。
理想的情况如上所示,可是I媒体它跟别人不一样。我们本地的数据一般情况下都有图片或者视频,在对接I媒体时只有图片。之前遇到这种情况都是将图片的链接发送给媒体,因为这些图片都是存储在我们的文件服务器上的。但是I媒体不想要图片链接,希望我们把图片下载好了然后发送过去。
图片总共有5张,还要分两组发送,一组两张一组三张,之后会给我们返回两个m_id
。 发送的数据结构如下所示:
const link_1 = [ 'link_1_1', 'link_1_2' ];
const link_2 = [ 'link_2_1', 'link_2_2', 'link_2_3' ]
const all_img_urls: [link_1, link_2]
const header = {
a: 'a',
b: 'b',
}
复制代码
如上所示,all_img_urls
中有两个元素,这两个元素是两个数组,里面包含了具体的每条url
。
这里的处理就比较麻烦了,得先将配置文件解析成两个,再将图片转化为二进制流,之后附在form
中发送过去。
关于解析二进制流,本意是想用https请求来获取的,后来发现request
也可以将文件转化成二进制流,文档在这里。
关于request
的操作其实是比较复杂的,这里我们选择了进阶用法——r.form()
。我们将除了二进制流以外的内容放在form
的header
中,二进制流append
到form
中。
首先我们需要定义请求配置文件:
const requestOptions = {
method: httpMethod
uri: api
headers: headers
localPath: url
}
复制代码
之后使用Promise.all
生成两个配置文件:
const generateRequsetOption = () => {
return Promise.all(_.map(all_img_urls, (imgUrls, index) => {
return {
method: 'POST',
uri: api,
headers: headers,
imgUrls: imgUrls
};
}));
}
复制代码
之所以使用Promise.all
是因为下面调用的时候还是需要使用Promise
,所以配置文件可以直接是两个Promise
对象。
接下来我们需要先将图片地址转化为二进制流,在获取到二进制流之后再进行下一步操作:
generateIqiyiRequsetOption()
.then((options) => {
Promise.all(_.map(options, (option) => {
Promise.all(_.map(option.img_urls, (img_url) => {
new Promise((_resolve, _reject) => {
request({ uri: imgUrl, encoding: null }, (err, response, body) => {
if(err){
return _reject(err)
}
return _resolve(body)
})
})
}))
.then((bodys) => {
// 下一步操作
})
}))
})
复制代码
这里的Promise
较多,主要是因为需要处理的东西比较多,首先我们要将两个配置文件循环出来,使用一次Promise.all
,之后我们将配置文件中的img_urls
循环出来,使用了一次Promise.all
,最后我们使用Promise
包裹我们请求二进制流的过程,使用了一次Promise
。确实比较复杂,但是也没有办法,就这样,我们在.then()
中获取的body
就是转换之后的二进制流。下面我们使用request
来发送数据。
.then((bodys) => {
return new Promise((_resolve, _reject) => {
// 定义request的主体内容
const r = request(_.omit(option, 'img_urls'), (err, response, body) => {
if(err){
return _reject(err);
}
return _resolve(body);
})
const form = r.form();
_.each(option.img_urls, (img_url, index) => {
form.append("file_${index}", bodys[index], { filename: img_url.split('/').pop() });
});
})
})
复制代码
在获取到二进制流之后我们使用了Promise
来处理配置信息,先定义request
的主体内容,之后根据配置文件新建form
,之后我们循环img_urls
,使用index
来获取到bodys
中的二进制流,还有就是添加一些文件名之类的信息。
至此,我们就完成了数据整合发送到主体内容,全部代码如下所示:
const link_1 = [ 'link_1_1', 'link_1_2' ];
const link_2 = [ 'link_2_1', 'link_2_2', 'link_2_3' ];
const all_img_urls: [link_1, link_2]
const header = {
a: 'a',
b: 'b',
};
const requestOptions = {
method: httpMethod
uri: api
headers: headers
localPath: url
};
const generateRequsetOption = () => {
return Promise.all(_.map(all_img_urls, (imgUrls, index) => {
return {
method: 'POST',
uri: api,
headers: headers,
imgUrls: imgUrls
};
}));
};
return new Promise ((resolve, reject) => {
generateIqiyiRequsetOption()
.then((options) => {
Promise.all(_.map(options, (option) => {
Promise.all(_.map(option.img_urls, (img_url) => {
return new Promise((_resolve, _reject) => {
request({ uri: imgUrl, encoding: null }, (err, response, body) => {
if(err){
return _reject(err);
}
return _resolve(body);
});
});
}))
.then((bodys) => {
return new Promise((_resolve, _reject) => {
const r = request(_.omit(option, 'img_urls'), (err, response, body) => {
if(err){
return _reject(err);
}
return _resolve(body);
});
const form = r.form();
_.each(option.img_urls, (img_url, index) => {
form.append("file_${index}", bodys[index], { filename: img_url.split('/').pop() })
});
})
})
}))
.then((results) => {
// 处理返回数据
})
})
});
复制代码
代码其实比较复杂,需要多看看才能理解,主要就是因为请求是异步的,可前端要同时得到反馈,所以只能一层又一层的嵌套Promise
,如果有同学有更好的想法可以评论留言,欢迎讨论。