• [记录点滴]在Ionic和Android中上传Blob图片


    [记录点滴]在Ionic和Android中上传Blob图片

    0x00 摘要

    本文是开发中的简略记录,具体涉及知识点有:Blob,Ionic,Android和Lua。

    起因是因为刚刚看到一篇关于Blob的文章你不知道的 Blob ,突然回忆起来在开发过程中也曾经使用过这种图片,所以就翻了翻代码,整理记录下来。

    0x01 Blob

    Blob(Binary Large Object)表示二进制类型的大对象,通常是影像、声音或多媒体文件。MySql/Oracle数据库中,就有一种Blob类型,专门存放二进制数据。

    在 JavaScript 中 Blob 对象表示一个不可变、原始数据的类文件对象,它不一定非得是大量数据,也可以表示一个小型文件的内容。另外,JavaScript 中的 File 接口是基于 Blob,继承 Blob 的功能并将其扩展使其支持用户系统上的文件。

    Blob 由一个可选字符串 type 和 blobParts 组成,其中, type 通常为 MIME 类型。

    MIME(Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型,常见有:超文本标记语言文本 .html text/html 、PNG图像 .png image/png 、普通文本 .txt text/plain 等。

    0x02 项目简述

    项目涉及方面比较多,有Ionic,Android,ios,后台处理图片部分是Lua。客户端需要上传小图片到后台。因为ios中上传图片这部分我没有参与,所以略过。

    以下代码做了简略和转换。

    0x02 Ionic

    Ionic上传过程中,主要使用Promise做异步控制,用$http做上传处理。

    function uploadPicture(file) {
          var q = $q.defer();
          var url = .....;
          var data = new FormData();
          var ext = file.split(',')[0].split(':')[1].split(';')[0].split('/')[1];
          data.append("file", dataURItoBlob(file), "picture." + ext); // 调了半天原来是这里Blob要加个name
          $http.post(url, data, {
              params: {
                token: getToken()
              },
              transformRequest: angular.identity,
              headers: {
                'Content-Type': undefined
              }
            })
            .success(function(result) {
              q.resolve(result);
            })
            .error(function(err) {
              q.reject(err);
            });
          return q.promise;
    }
    

    base64字符串转图片格式的函数在这里

    function dataURItoBlob(dataURI) {
        // convert base64/URLEncoded data component to raw binary data held in a string
        var byteString;
        if (dataURI.split(',')[0].indexOf('base64') >= 0)
          byteString = atob(dataURI.split(',')[1]);
        else
          byteString = unescape(dataURI.split(',')[1]);
    
        // separate out the mime component
        var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
    
        // write the bytes of the string to a typed array
        var ia = new Uint8Array(byteString.length);
        for (var i = 0; i < byteString.length; i++) {
          ia[i] = byteString.charCodeAt(i);
        }
        return new Blob([ia], {
          name: 'picture',
          type: mimeString
        });
    }
    

    0x03 Android

    网络传输使用了retrofit2。

    public void uploadAvatar(Observer<Response> observer, int userId, String filePath) {
            checkOauth();
            File file = new File(filePath);
            RequestBody requestBody = RequestBody.create(MediaType.parse("image/*"), file);
            MultipartBody.Part body = MultipartBody.Part.createFormData("file", file.getName(), requestBody);
    
            networkService.uploadAvatar(userId, body)
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(observer);
        }
    
    // 这里是NetworkService实现
    @Multipart
    @POST(Constants.Url + "{id}")
    Observable<Response> uploadAvatar(@Path("id") int id, @Part MultipartBody.Part file);
    

    0x04 Lua

    后台中图片接口是用Lua来处理。

    res, err = REQUEST.get_upload_file()
    if _.isEmpty(res) then
         ngx.say(RESPONSE.error(-1, err, 404))
    end
    

    当时参考了解决nginx + lua 上传文件问题。对原文代码做了修改以匹配我们实际环境。

    -- 注意lua-resty-upload模块只能上传有boundary的post请求体,没有boundary的话需要使用socket来进行传输。
    local UPLOAD = require "resty.upload"
    
    function _M.get_upload_file() 
        local chunk_size = 4096  --如果不设置默认是4096.
        local form,err = UPLOAD:new(chunk_size)
        local sha1 = RESTY_SHA1:new()  --测试时可以用来verify
        local file
        local filelen=0
        local filename
        local osfilepath = CONF.const()['UPLOAD_FILE_PATH']     
        local i=0
        local response 
    
        if not _.isEmpty(err) then
            ngx.log(LOGGER.e("form is: ", form, ", err is: ", err))
        end
    
        form:set_timeout(0) -- form:set_timeout(1000) -- 1 sec
    
        while true do
            local typ, res, err = form:read()        
            if not typ then
                ngx.log(LOGGER.e("failed to read: ", err))
                return false
            end
    
            if typ == "header" then
                if res[1] ~= "Content-Type" and res[1] ~= "Content-Length" then -- 对比原文增加了一个判断
                    filename = get_filename(res[2])
                    if filename then
                        i=i+1
                        filepath = osfilepath .. filename
                        file = io.open(filepath,"wb+") -- 对比原文增加了b
                        if not file then
                            ngx.log(LOGGER.e("failed to open file "))
                            return false
                        end
                    else
                    end
                end
            elseif typ == "body" then
                if file then
                    filelen= filelen + tonumber(string.len(res))    
                    file:write(res)
                    sha1:update(res) -- verify in dev env
                else
                end
            elseif typ == "part_end" then
                if file then
                    file:close()
                    file = nil
                    ngx.say("file upload success")
                    local sha1_sum = sha1:final() -- verify in dev env
                    sha1:reset()
                end
            elseif typ == "eof" then
                break
            else
                -- do nothing
            end
        end
        if i==0 then
            ngx.log(LOGGER.e("please upload at least one file!"))
            return false
        end
    
        response = {
            result = true, 
            fn = filename, 
            fp = filepath
        }
        return response
    end
    

    0x05 参考

    你不知道的 Blob

    解决nginx + lua 上传文件问题

  • 相关阅读:
    【转】SqlServer Text类型字段超过8000字处理
    uniapp项目运行时一直发http://localhost:8080/sockjs-node/info?t=1462183700002请求
    【转】chrome 浏览器调用 ocx 插件
    【转】javascript检测浏览器插件
    【转】web错误代码ERR_BLOCKED_BY_RESPONSE
    我是如何将Sublime Text 4 设置成中文版
    【转】用好 Vue 中 v-for 循环的 7 种方法
    【转】JavaScript console.log %c %o %s %d %f
    [JavaScript]UMD模块
    leetcode-课程表I和课程表II
  • 原文地址:https://www.cnblogs.com/rossiXYZ/p/13123677.html
Copyright © 2020-2023  润新知