为什么很多中国人去菲律宾做网站,网站维护工作的基本内容,旅游景区网站建设规划,线上营销渠道有哪些2019独角兽企业重金招聘Python工程师标准 我们先看看linkface给开放的接口#xff1a; 字段类型必需描述api_idstring是API 账户api_secretstring是API 密钥selfie_filefile见下方注释需上传的图片文件 1#xff0c;上传本地图片进行检测时选取此参数selfie_ur… 2019独角兽企业重金招聘Python工程师标准 我们先看看linkface给开放的接口 字段类型必需描述api_idstring是API 账户api_secretstring是API 密钥selfie_filefile见下方注释需上传的图片文件 1上传本地图片进行检测时选取此参数selfie_urlstring见下方注释图片 1 的网络地址采用抓取网络图片方式时需选取此参数selfie_image_idfile见下方注释图片 1 的id在云端上传过图片可采用historical_selfie_filefile见下方注释需上传的图片文件 2上传本地图片进行检测时选取此参数historical_selfie_urlstring见下方注释图片 2 的网络地址采用抓取网络图片方式时需选取此参数historical_selfie_image_idstring见下方注释图片 2 的id在云端上传过图片可采用selfie_auto_rotateboolean否值为 true 时对图片 1 进行自动旋转。默认值为 false不旋转historical_selfie_auto_rotateboolean否值为 true 时对图片 2 进行自动旋转。默认值为 false不旋转 如文件所示接口需要同时上传两个文件和两个字段一般我们的web前端就很简单了两个file类型的input组成的form提交就可以若想实现文件的异步上传通俗的方式就是安装浏览器安全插件或者就是使用form表单的提交target指向为iframe然后将iframe隐藏使用视窗的父子级调用完成但是这仍需要我们使用form组件选择文件很显然这样会使得我们的移动APP体验极差我们期望的就是使用相机拍完照然后直接异步上传执行检测当然我们可以使用XMLHTTPReauest2拼接一个formatdata上传 //不完全代码
let formData new FormData();
formData.append(fileName,input.files[0]);
xhr.open(post, encodeURI(url));
xhr.send(formData); 但是在web端如果用户不使用input选择文件我们是无法私自获取并上传文件的这个浏览器的安全机制想想如果可以拼接file://私自获取文件我们还安全么 那么针对于cordova plugin 就相当于我们浏览器的插件了道理是一定的通过js的方式调用底层接口。我们首先能够想得到的就是file-transfer这个插件但是很遗憾的告诉你这个插件一次只能上传一个文件 https://github.com/apache/cordova-plugin-file-transfer Parameters:fileURL: Filesystem URL representing the file on the device or a data URI. For backwards compatibility, this can also be the full path of the file on the device. (See Backwards Compatibility Notes below)server: URL of the server to receive the file, as encoded by encodeURI().successCallback: A callback that is passed a FileUploadResult object. (Function)errorCallback: A callback that executes if an error occurs retrieving the FileUploadResult. Invoked with a FileTransferError object. (Function)options: Optional parameters (Object). Valid keys:fileKey: The name of the form element. Defaults to file. (DOMString)
fileName: The file name to use when saving the file on the server. Defaults to image.jpg. (DOMString)
httpMethod: The HTTP method to use - either PUT or POST. Defaults to POST. (DOMString)
mimeType: The mime type of the data to upload. Defaults to image/jpeg. (DOMString)
params: A set of optional key/value pairs to pass in the HTTP request. (Object, key/value - DOMString)
chunkedMode: Whether to upload the data in chunked streaming mode. Defaults to true. (Boolean)
headers: A map of header name/header values. Use an array to specify more than one value. On iOS, FireOS, and Android, if a header named Content-Type is present, multipart form data will NOT be used. (Object)
trustAllHosts: Optional parameter, defaults to false. If set to true, it accepts all security certificates. This is useful since Android rejects self-signed security certificates. Not recommended for production use. Supported on Android and iOS. (boolean) 我真搞不懂既然cordova plugin封装为啥不封装成文件数组接口呢支持多文件和困难么那么我们就来看看他的源码 boolean multipartFormUpload (headers null) || !headers.has(Content-Type);if (multipartFormUpload) {conn.setRequestProperty(Content-Type, multipart/form-data; boundary BOUNDARY);}// Set the cookies on the responseString cookie getCookies(target);if (cookie ! null) {conn.setRequestProperty(Cookie, cookie);}// Handle the other headersif (headers ! null) {addHeadersToRequest(conn, headers);}/** Store the non-file portions of the multipart data as a string, so that we can add it* to the contentSize, since it is part of the body of the HTTP request.*/StringBuilder beforeData new StringBuilder();try {for (Iterator? iter params.keys(); iter.hasNext();) {Object key iter.next();if(!String.valueOf(key).equals(headers)){beforeData.append(LINE_START).append(BOUNDARY).append(LINE_END);beforeData.append(Content-Disposition: form-data; name\).append(key.toString()).append();beforeData.append(LINE_END).append(LINE_END);beforeData.append(params.getString(key.toString()));beforeData.append(LINE_END);}}} catch (JSONException e) {Log.e(LOG_TAG, e.getMessage(), e);}beforeData.append(LINE_START).append(BOUNDARY).append(LINE_END);beforeData.append(Content-Disposition: form-data; name\).append(fileKey).append(\;);beforeData.append( filename\).append(fileName).append().append(LINE_END);beforeData.append(Content-Type: ).append(mimeType).append(LINE_END).append(LINE_END);byte[] beforeDataBytes beforeData.toString().getBytes(UTF-8);byte[] tailParamsBytes (LINE_END LINE_START BOUNDARY LINE_START LINE_END).getBytes(UTF-8); 看到了吗它是拼接了报文这就是能够解释它为啥还需要依赖 cordova-plugin-file这个插件了它可以直接获取文件ArrayBuffer很聪明啊真的很聪明为什么拼报文岂不是很麻烦正常我么使用java的http client是需要依赖 httpclient-4.0.1.jar commons-codec-1.3.jar apache-mime4j-0.6.jar httpcore-4.0.1.jar httpmime-4.0.1.jar 这无形之中就增大了app的大小作为卡插拔式的插件大小也是一个硬伤所以封装插件的同学们学习吧人家可不是盖的拼接报文自然使得插件不需要依赖那些包了。 我们开脑补一下http报文协议 一个HTTP请求报文由请求行request line、请求头部header、空行和请求数据4个部分组成下图给出了请求报文的一般格式。 所以按照标准拼写报文也是可以的。 但是我是一个H5工程师我首先会使用H5技术去解决这件事不然我就只能发挥java技能更改file-transfer这个插件了。XHR拼接formdata可以是file也可以是一个blob我曾将想过是不是有接口能够模拟封装input的file或者使用FileReader然而还是那句话浏览器为了安全不会让我们自己拼接file:// 的但是cordova跨平台可以访问文件系统你可以看一下 https://github.com/apache/cordova-plugin-file里http-equivContent-Security-Policy相关的描述毕竟我们开发的是移动app这个功能是不可缺少的我们使用cordova的file plugin还是可以获取文件的我们来看看ionic2提供的接口(http://ionicframework.com/docs/v2/native/file/ ): readAsArrayBuffer(path, file) Read file and return data as an ArrayBuffer. ParamTypeDetailspathstring Base FileSystem. Please refer to the iOS and Android filesystems above filestring Name of file, relative to path. Returns: PromiseArrayBuffer|FileError Returns a Promise that resolves with the contents of the file as ArrayBuffer or rejects with an error. 惊喜吧有个这个我们就能够自己拼写blob类型的formdata了话不多说我们直接上代码 先写封装一个文件转换类file-convert-util.ts import {File, FileError} from ionic-native;
/**** author 赵俊明*/export class FileConvertUtil {constructor() {}//讲文件转换为Blobpublic static convertFileToBlob(fullFilePath: string): PromiseBlob|FileError {return new Promise((resolve, reject) {FileConvertUtil.convertFileToArrayBuffer(fullFilePath).then((arrayBuffer) {resolve(new Blob([arrayBuffer], {type: image/ FileConvertUtil.extractFileType(fullFilePath)}));}).catch((reason) {reject(reason);});});}//将文件装换为ArrayBufferpublic static convertFileToArrayBuffer(fullFilePath: string): PromiseArrayBuffer | FileError {return File.readAsArrayBuffer(FileConvertUtil.extractFilePath(fullFilePath), FileConvertUtil.extractFileName(fullFilePath));}//截取文件路径public static extractFilePath(fullFilePath: string): string {return fullFilePath.substr(0, fullFilePath.lastIndexOf(/));}//截取文件名称public static extractFileName(fullFilePath: string): string {return fullFilePath.substr(fullFilePath.lastIndexOf(/) 1);}//截取文件类型public static extractFileType(fullFilePath: string): string {return fullFilePath.split(.)[1];}} 基于XHR2的uploadxhr-multipart-upload.ts import {BrowserXhr} from angular/http;
import {FileConvertUtil} from ./file-convert-util;
import {FileError} from ionic-native;
import {Injectable, Component} from angular/core;
/*** author zhaojunming*/export class XHRMultipartFileUpload {private static browserXhr new BrowserXhr();constructor() {}public static upload(url: string, files: {name: string,path: string}[], params: any): Promiseany {const xhr XHRMultipartFileUpload.browserXhr.build();xhr.open(post, encodeURI(url));let formData new FormData();return new Promise((resolve, reject) {if (params) {for (let _v in params) {if (params.hasOwnProperty(_v)) {formData.append(_v, params[_v]);}}}let blobPromiseList: ArrayPromiseBlob|FileError [];files.forEach((file) {blobPromiseList.push(FileConvertUtil.convertFileToBlob(file.path));});Promise.all(blobPromiseList).then((result) {result.forEach((blob, index) {formData.append(files[index].name, blob, FileConvertUtil.extractFileName(files[index].path));});xhr.onreadystatechange () {if (xhr.readyState 4) {if (xhr.status 200) {resolve(JSON.parse(xhr.responseText));} else {reject({code: xhr.status, message: JSON.parse(xhr.responseText)});}}}xhr.send(formData);}).catch((reason) {reject(reason);});});}} 调用linkface的provider,linkface-verfication.ts: /**** author 赵俊明*/import {Injectable, Component} from angular/core;
import {XHRMultipartFileUpload} from ./xhr-multipart-upload;
import {Storage, LocalStorage} from ionic-angular;//400 错误码对应信息
const ERROR_MAPPING {ENCODING_ERROR: 参数非UTF-8编码,DOWNLOAD_TIMEOUT: 网络地址图片获取超时,DOWNLOAD_ERROR: 网络地址图片获取失败,IMAGE_FILE_SIZE_TOO_BIG: 图片体积过大 ,IMAGE_ID_NOT_EXIST: 图片不存在,NO_FACE_DETECTED: 图片未检测出人脸 ,CORRUPT_IMAGE: 文件不是图片文件或已经损坏,INVALID_IMAGE_FORMAT_OR_SIZE: 图片大小或格式不符合要求,INVALID_ARGUMENT: 请求参数错误,UNAUTHORIZED: 账号或密钥错误,KEY_EXPIRED: 账号过期,RATE_LIMIT_EXCEEDED: 调用频率超出限额,NO_PERMISSION: 无调用权限,NOT_FOUND: 请求路径错误,INTERNAL_ERROR: 服务器内部错误
};Injectable()
export class LinkFaceVerfication {//普通照片比对URLprivate historicalSelfieVerificationURL https://v1-auth-api.visioncloudapi.com/identity/historical_selfie_verification;//公安水印照片与普通照片比对URLprivate selfieWatermarkVerificationURL https://v1-auth-api.visioncloudapi.com/identity/selfie_watermark_verification;private apiId: string;private apiSecret: string;//LocalStorageprivate storage new Storage(LocalStorage);constructor() {this.getApiId().then(apiId {this.apiId apiId || 6b666502c4324026b8604c8001a2cd14;}).catch(() {this.apiId 6b666502c4324026b8604c8001a2cd14;});this.getApiSecret().then(apiSecret {this.apiSecret apiSecret || 28cf8b8693e54d0b930d0a5089831841;}).catch(() {this.apiSecret 28cf8b8693e54d0b930d0a5089831841;});}//普通照片比对public historicalSelfieVerification(selfie_file: string, historical_selfie_file: string, selfie_auto_rotate: boolean true, historical_selfie_auto_rotate: boolean true): Promiseany {let params {api_id: this.apiId,api_secret: this.apiSecret,selfie_auto_rotate: selfie_auto_rotate,historical_selfie_auto_rotate: historical_selfie_auto_rotate};let files []files.push({name: selfie_file, path: selfie_file});files.push({name: historical_selfie_file, path: historical_selfie_file});return new Promise((resolve, reject) {XHRMultipartFileUpload.upload(this.historicalSelfieVerificationURL, files, params).then(result {resolve(result);}).catch(error {if (error error.code 400) {reject(ERROR_MAPPING[error.message.status]);} else {reject(JSON.stringify(error));}});});}//公安水印照片与普通照片比对public selfieWatermarkVerification(selfie_file: string, watermark_picture_file: string): Promiseany {let params {api_id: this.apiId, api_secret: this.apiSecret};let files []files.push({name: selfie_file, path: selfie_file});files.push({name: watermark_picture_file, path: watermark_picture_file});return new Promise((resolve, reject) {XHRMultipartFileUpload.upload(this.selfieWatermarkVerificationURL, files, params).then(result {resolve(result);}).catch(error {if (error error.code 400) {reject(ERROR_MAPPING[error.message.status]);} else {reject(JSON.stringify(error));}});});}setApiId(apiId): boolean {if (apiId) {this.apiId apiId;this.storage.set(apiId, apiId);return true;}return false;}setApiSecret(apiSecret): boolean {if (apiSecret) {this.apiSecret apiSecret;this.storage.set(apiSecret, apiSecret);return true;}return false;}getApiId(): Promisestring {return this.storage.get(apiId);}getApiSecret(): Promisestring {return this.storage.get(apiSecret);}} 看看我们怎么调用 this.linkFaceVerfication.historicalSelfieVerification(this.selfie_file, this.historical_selfie_file, true, true).then(result {this.confidence (result.confidence * 100).toFixed(2);this.uploading false;}).catch(reason {this.toastMessage(reason);this.uploading false;}); 我们来看看效果 转载于:https://my.oschina.net/u/259422/blog/747399