【原】Framework7下打包后的APP支持图片上传(支持七牛)

前言:

Framework7确实是一个不错的框架,接合Cordova写跨平台应用方便快捷,但其中难免会遇到一些问题,比如:如何支持图片上传。

本文涉及的APP用的是七牛的JS-SDK上传图片,生成、获取七牛对象存储的UPTOKEN不在本文讨论范围之内,需要自己参照官方文档

准备工作:

  1. 去Cordova项目路径下,先安装两个插件:
    # cordova plugin add cordova-plugin-file
    # cordova plugin add cordova-plugin-image-picker --variable PHOTO_LIBRARY_USAGE_DESCRIPTION="获取权限时的描述信息"

    插件项目主页:

    https://github.com/wymsee/cordova-imagePicker

    https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-file/

  2. 引入qiniu.min.js文件到Framework7中。

 

本文涉及的基本思路是:(可有其他方案,会简便很多)

点击屏幕一个a标签后,开启文件选择框(由项目cordova-imagePicker实现),选择文件后,转换,调用七牛的SDK上传文件(含AJAX请求获取UPTOKEN)。

相关主要代码:

// 以上省略 注意,下文中的app指的是 new Framework7()生成的,如果在template文件中,可由methods下定义的任何一个函数,使用 this.$app 获取该对象。
    window.imagePicker.getPictures(
        function (results) {
            for (var i = 0; i < results.length; i++) {
            // results[i] 是本地路径,基本格式为: file:///path/fileName.jpg

            // key 是用于七牛对象存储的,可以理解为上传以后的文件名
            var key = "users/avatar/" + app.utils.id('xxxx-xxxx-xxxx-xxxx') // 此处是用Framework7的utils生成一个ID
            var putExtra = {
                fname: "",  // 原文件名,可为空
                params: {}, // 附带参数
                mimeType: [] || null // 允许的文件MIME类型(此处为允许所有)
            };
            var config = {
                useCdnDomain: true, // 使用CDN域名
                region: qiniu.region.z0 // 存储区域
            };

            var error = function (err) {
                console.log(err); // err是个对象,里面包含三个属性
                app.dialog.alert(err.message, function () { })
            };
            var next = function (res) {
            // res里面包括已上传大小(res.total.loaded),总共大小(res.total.total),以及进度(res.total.percent), 详情可参考七牛JS-SDK文档
            }
            var complete = function (response) {
                console.log(response)
            }

            // 上传Token,为了上传七牛服务器的时候,进行验证使用。
            // 由自己服务器根据bucket,accessKey,secretKey等生成。
            var uptoken = "xxxxxxxxxxxxxxxx"

            // 开始依据本地路径读取文件,之所以这么做,因为如果直接传入results[i]进入qiniu.upload函数的第一个参数,那么最后上传的只是一个本地路径,并非其文件。
            // 此步骤的目的是,读取本地文件,并转换传入
            window.resolveLocalFileSystemURL(results[i], function (entry) {
                entry.file(function (file) {
                    var reader = new FileReader();

                    reader.onloadend = function () {
                        // this.result 是Base64编码的图片文件,开始Base64至Blob对象。
                        // 此处感谢 https://www.cnblogs.com/jiujiaoyangkang/p/9396043.html 提供思路。
                        var arr = this.result.split(','), mime = arr[0].match(/:(.*?);/)[1], bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
                        while (n--) {
                            u8arr[n] = bstr.charCodeAt(n);
                        }
                        var blob = new Blob([u8arr], { type: mime });

                        // 转换完毕,得到blob。
                        // 开始调用sdk上传接口获得相应的observable,控制上传和暂停。 
                        // 注意:如果此处函数的第一个参数直接传入this.result,那么去七牛后台查看上传数据的话,会是一个base64编码的文件。
                        observable = qiniu.upload(blob, key, uptoken, putExtra, config);
                        observable.subscribe({
                            next: next,         // 实时变动
                            error: error,       // 发生错误的时候
                            complete: complete  // 上传完成的时候
                        })
                    };

                 // 以Base64的方式读取
                 reader.readAsDataURL(file);
                 })
             });
          }
      }, function (error) {
          console.log('Error: ' + error);

          app.dialog.alert('Error: ' + error)
      }, {
          maximumImagesCount: 1,  // 每次运行可选择的图片
          uality: 50 // 图片质量(最大为100)
      }
   );
// 以下省略

 

以上代码中,是从一个函数中截取出来的,这里面有较大的一部分都在做读取文件,并转换成Blob对象(花了我好长时间去找资料并测试)。

如果用input标签获取到的file对象其实并不需要做这类操作,直接传入qiniu.upload函数就好;但在调试过程中,如果直接使用input标签选择文件,iPhone SE模拟器下每次都引起闪退(Android并未尝试)。据查资料得知,可能是因为布局或版本导致,只不过解决方案并不想深究。

【原】在Golang程序中支持RS256验证的JWT

前言:

什么是JWT就不做介绍了,本文只介绍如何基于JWT做支持RS256验证的Go程序。

几个有用的URL:

  1. https://godoc.org/github.com/dgrijalva/jwt-go#example-Parse–Hmac
  2. https://jwt.io/
  3. https://github.com/dgrijalva/jwt-go

其实官网提供了很多各种语言的SDK,直接拿来用就好(本文选用的是github.com/dgrijalva/jwt-go),但查询资料途中,大部分都是HMAC验证(作为对称加密的一种,总有种不安的感觉),于是根据自己的实践,编写本文。

准备工作:

此处基于Linux环境下,需要openssl以及Go环境的支持

生成一个私钥证书(做签发用)

# openssl genrsa -out private.key 2048

基于私钥生成一个公钥证书(做验证用)

# openssl rsa -in private.key -pubout > public.key

开始写代码了:(以下代码经过删减与修改,主要是调用github.com/dgrijalva/jwt-go项目)

import (
        ...
        jwt "github.com/dgrijalva/jwt-go"
        ...
)

var (
  publicKey  *rsa.PublicKey
  privateKey *rsa.PrivateKey
)


func init() {
  publicKeyByte, err := ioutil.ReadFile("公钥的路径/public.key")
  if err != nil {
    log.Println(err.Error())
  }
  publicKey, err = jwt.ParseRSAPublicKeyFromPEM(publicKeyByte)

  privateKeyByte, err := ioutil.ReadFile("私钥的路径/private.key")
  if err != nil {
    log.Println(err.Error())
  }
  privateKey, _ = jwt.ParseRSAPrivateKeyFromPEM(privateKeyByte)
}

// createToken 生成一个RS256验证的Token
// Token里面包括的值,可以自己根据情况添加,
func createToken() (tokenStr string, err error) {
  token := jwt.NewWithClaims(jwt.SigningMethodRS256, jwt.MapClaims{
    "iat":      time.Now().Unix(), // Token颁发时间
    "nbf":      time.Now().Unix(), // Token生效时间
    "exp":      time.Now().Add(time.Hour * 24).Unix(), // Token过期时间,目前是24小时
    "iss":      "liwenbin.com", // 颁发者
    "sub":      "AuthToken", // 主题
//  "role":     "guest", // 角色(附加)
  })
  return token.SignedString(privateKey)
}

// getSubFromToken 获取Token的主题(也可以更改获取其他值)
// 参数tokenStr指的是 从客户端传来的待验证Token
// 验证Token过程中,如果Token生成过程中,指定了iat与exp参数值,将会自动根据时间戳进行时间验证
func getSubFromToken(tokenStr string) (sub string, err error) {
  // 基于公钥验证Token合法性
  token, err := jwt.Parse(tokenStr, func(token *jwt.Token) (interface{}, error) {
    // 基于JWT的第一部分中的alg字段值进行一次验证
    if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
      return nil, errors.New("验证Token的加密类型错误")
    }
    return publicKey, nil
  })
  if err != nil {
    return
  }

  if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
    return claims["sub"].(string), nil
  }

  return "", errors.New("Token无效或者无对应值")
}

 

这样,就搞定了,注意要把公私钥的路径确定好哈。

生成的Token分为3个部分(均基于BASE64编码,以“.”区分),第一个部分是定义,第二个部分是你生成Token时设置的各项值,第三个是签名。

最后再次感谢项目:github.com/dgrijalva/jwt-go

【原】编译FFMPEG过程中发生的几个耗时解决的问题

其实只是几个我在编译过程中遇到的错误,记录下来也可以给大家做个小提示。

一、关于ERROR:* not found using pkg-config的问题。

遇到这类问题就先安装对应的软件呗,yum安装以及源码编译过程就不啰嗦了,官网、技术博客很多介绍;但有时候,明明已经安装好了(记得安装devel包,例如:# yum install opus-devel等等),但依旧无法被识别,此时请确定这个变量“PKG_CONFIG_PATH”是否被赋予了正确的值。

# echo $PKG_CONFIG_PATH

如果显示为空或者只显示了一个目录记录,那可能是这里出的问题。(因为:参照互联网上的编译安装步骤,你的那些依赖软件会分散在两个地方。所以,一般是两个不同的目录的话,才是正确的。)

(可选操作)此时请确定目录路径是否包含不同文件:”/root/ffmpeg_build/lib/pkgconfig“以及”/usr/local/lib/pkgconfig

然后执行命令:

# export PKG_CONFIG_PATH=/root/ffmpeg_build/lib/pkgconfig:/usr/local/lib/pkgconfig

即可。

二、个人一直使用的编译参数。

./configure –prefix=/root/ffmpeg_build –pkg-config-flags=–static –extra-cflags=-I/root/ffmpeg_build/include –extra-ldflags=-L/root/ffmpeg_build/lib –extra-libs=-lpthread –extra-libs=-lm –bindir=/root/bin –enable-gpl –enable-libfdk_aac –enable-libfreetype –enable-libmp3lame –enable-libopus –enable-libvorbis –enable-libvpx –enable-libx264 –enable-libx265 –enable-nonfree –enable-libass –pkg-config-flags=”–static”


参考链接:

  1. https://trac.ffmpeg.org/wiki/CompilationGuide/Centos