時間: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
生成兩個配置文件:npm
const generateRequsetOption = () => {
return Promise.all(_.map(all_img_urls, (imgUrls, index) => {
return {
method: 'POST',
uri: api,
headers: headers,
imgUrls: imgUrls
};
}));
}
複製代碼
之因此使用Promise.all
是由於下面調用的時候仍是須要使用Promise
,因此配置文件能夠直接是兩個Promise
對象。
接下來咱們須要先將圖片地址轉化爲二進制流,在獲取到二進制流以後再進行下一步操做:api
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
中的二進制流,還有就是添加一些文件名之類的信息。
至此,咱們就完成了數據整合發送到主體內容,所有代碼以下所示:bash
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
,若是有同窗有更好的想法能夠評論留言,歡迎討論。服務器