將圖片轉化爲二進制流附在表單中發送出去

時間: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()。咱們將除了二進制流之外的內容放在formheader中,二進制流appendform中。
首先咱們須要定義請求配置文件:數據庫

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,若是有同窗有更好的想法能夠評論留言,歡迎討論。服務器

相關文章
相關標籤/搜索