我正在开发Nativscript-Vue移动应用,我需要能够从图片库中选择一个文件并将其上传到在线文件管理器(我使用000webhost.com)。
我使用了从NativeScript网站获得的代码示例,并且能够毫无问题地获取图片,但是我无法将其上传到WebHost(日志显示上传成功,并且存在没有显示错误,但由于某些原因我的图片文件夹仍然为空)。
这是我的代码:
<template>
<Page class="page">
<ActionBar title="imagepicker + background-http" class="action-bar"></ActionBar>
<GridLayout rows="*, auto">
<GridLayout v-if="!showWelcome" rows="auto auto auto, *">
<Progress :value="event && event.eventData ? event.eventData.currentBytes : 0"
:maxValue="event && event.eventData ? event.eventData.totalBytes : 0">
</Progress>
<Label row="1" v-if="event && event.eventData && event.eventData.currentBytes !== NaN"
class="m-10 text" :text="'Transferred: ' + event.eventData.currentBytes / 1000 + ' KB'"></Label>
<Label row="2" class="m-10 text" text="Events"></Label>
<ListView row="3" for="item in eventLog">
<v-template>
<StackLayout class="t-12">
<Label :text="item.eventTitle" textWrap="true"></Label>
<Label v-if="item.eventData && item.eventData.error"
:text="item.eventData ? 'Error: ' + item.eventData.error : ''"
textWrap="true"></Label>
<Label v-if="item.eventData && item.eventData.body"
:text="item.eventData ? 'Body: ' + item.eventData.body : ''"
textWrap="true"></Label>
<Label v-if="item.eventData && item.eventData.raw"
:text="item.eventData ? 'Raw: ' + item.eventData.raw : ''"
textWrap="true"></Label>
</StackLayout>
</v-template>
</ListView>
</GridLayout>
<StackLayout v-if="showWelcome" verticalAlignment="middle">
<Label class="m-10 nativescript-label text" text="{N}"></Label>
<Label class="m-10 text" v-if="showWelcome" text="This sample app shows how to pick an image with"
textWrap="true"></Label>
<Label class="m-10 text plugin" text="nativescript-imagepicker"></Label>
<Label class="m-10 text" v-if="showWelcome" text="and upload it using"
textWrap="true"></Label>
<Label class="m-10 text plugin" text="nativescript-background-http"></Label>
</StackLayout>
<Button class="m-b-10 m-t-10 t-20" row="1" text="Choose image to upload" @tap="onSelectImageTap($event)"></Button>
</GridLayout>
</Page>
</template>
<script>
import VueRx from "../vue-rx";
import Vue from "nativescript-vue";
const app = require("tns-core-modules/application");
const platform = require("platform");
const fs = require("file-system");
const imagePicker = require("nativescript-imagepicker");
const rxjs = require("rxjs");
const operators = require("rxjs/operators");
const bgHttp = require("nativescript-background-http");
Vue.use(VueRx);
// Vue.config.silent = false; // uncomment for debugging purposes
export default {
data() {
return {
showWelcome: true,
session: bgHttp.session("image-upload"),
currentFileNameBeingUploaded: ""
};
},
subscriptions() {
this.event$ = new rxjs.BehaviorSubject({});
return {
event: this.event$,
eventLog: this.event$.pipe(
operators.sampleTime(200),
operators.concatMap(value => rxjs.of(value)),
operators.scan((acc, logEntry) => {
acc.push(logEntry);
return acc;
}, []),
// emit only logs for the this.currentFileNameBeingUploaded
operators.map(allLogs => allLogs.filter(logEntry => !!logEntry && logEntry.eventTitle && logEntry.eventTitle.indexOf(this.currentFileNameBeingUploaded) > 0))
)
};
},
methods: {
onSelectImageTap() {
let context = imagePicker.create({
mode: "single"
});
this.startSelection(context);
},
startSelection(context) {
context
.authorize()
.then(() => {
return context.present();
})
.then(selection => {
this.showWelcome = false;
let imageAsset = selection.length > 0 ? selection[
0] : null;
if (imageAsset) {
this.getImageFilePath(imageAsset).then(path => {
console.log(`path: ${path}`);
this.uploadImage(path);
});
}
})
.catch(function(e) {
console.log(e);
});
},
uploadImage(path) {
let file = fs.File.fromPath(path);
this.currentFileNameBeingUploaded = file.path.substr(
file.path.lastIndexOf("/") + 1
);
let request = this.createNewRequest();
request.description = "uploading image " + file.path;
request.headers["File-Name"] = this.currentFileNameBeingUploaded;
// -----> multipart upload
// var params = [{
// name: "test",
// value: "value"
// },
// {
// name: "fileToUpload",
// filename: file.path,
// mimeType: "image/jpeg"
// }
// ];
// var task = this.session.multipartUpload(params, request);
// <----- multipart upload
let task = this.session.uploadFile(file.path, request);
task.on("progress", this.onEvent.bind(this));
task.on("error", this.onEvent.bind(this));
task.on("responded", this.onEvent.bind(this));
task.on("complete", this.onEvent.bind(this));
},
createNewRequest() {
let url;
// NOTE: using https://httpbin.org/post for testing purposes,
// you'll need to use your own service in real-world app
if (platform.isIOS) {
url = "https://ipaccovoiturage.000webhostapp.com/pictures";
} else {
url = "https://ipaccovoiturage.000webhostapp.com/pictures";
}
let request = {
url: url,
method: "POST",
headers: {
"Content-Type": "application/octet-stream"
},
description: "uploading file...",
androidAutoDeleteAfterUpload: false,
androidNotificationTitle: "NativeScript HTTP background"
};
return request;
},
getImageFilePath(imageAsset) {
return new Promise(resolve => {
if (platform.isIOS) {
const options = PHImageRequestOptions.new();
options.synchronous = true;
options.version =
PHImageRequestOptionsVersion.Current;
options.deliveryMode =
PHImageRequestOptionsDeliveryMode.HighQualityFormat;
PHImageManager.defaultManager().requestImageDataForAssetOptionsResultHandler(
imageAsset.ios,
options,
nsData => {
// create file from image asset and return its path
const tempFolderPath = fs.knownFolders
.temp()
.getFolder("nsimagepicker").path;
const tempFilePath = fs.path.join(
tempFolderPath,
Date.now() + ".jpg"
);
nsData.writeToFileAtomically(
tempFilePath, true);
resolve(tempFilePath);
}
);
} else {
// return imageAsset.android, since it 's the path of the file
resolve(imageAsset.android);
}
});
},
onEvent(e) {
let eventEntry = {
eventTitle: e.eventName + " " + e.object.description,
eventData: {
error: e.error ? e.error.toString() : e.error,
currentBytes: e.currentBytes,
totalBytes: e.totalBytes,
body: e.data
// raw: JSON.stringify(e) // uncomment for debugging purposes
}
};
this.event$.next(eventEntry);
}
}
};
</script>
<style scoped>
.home-panel {
vertical-align: center;
font-size: 20;
margin: 15;
}
.description-label {
margin-bottom: 15;
}
.text {
text-align:
center;
font-size: 18px;
}
.plugin {
font-weight: 600;
font-size: 23px;
}
.nativescript-label {
font-size: 60px;
background-color: #3d5afe;
font-weight: 600;
color: white;
border-radius: 20px/20px;
width: 230px;
height: 230px;
}
</style>
我以为WebHost可能是问题所在,但是我已经能够使用PHP和HTML插入照片(不幸的是,NativeScript-Vue不允许HTML)。
答案 0 :(得分:1)
我在纯JavaScript中也遇到了类似的问题。我在上面工作了几天。 @Manoj的答案对我不起作用。我必须使用multipartUpload,因为我要发送其他参数。
确保将请求中的名称参数(fileToUpload)与您的服务期望的名称匹配。就我而言是“文件”。
服务API签名如下:
public async Task<IActionResult> Upload(string listingId, IFormFile file)
我的要求:
const request = {
url: "yoururl",
method: "POST",
headers: {
"Content-Type": "multipart/form-data",
"Authorization": token
},
description: `Uploading image ${name}`,
androidAutoDeleteAfterUpload: true,
androidNotificationTitle: "HTTP background"
};
const params = [
{
name: "listingId",
value: 2
},
{
name: "file", // Note it is not fileToUpload but file instead.
filename: path,
mimeType: "image/jpeg"
}
];
const task = session.multipartUpload(params, request);
我希望它会有所帮助。顺便说一下,Content-Type multipart / form-data和application / octet-stream都对我有用,但是我使用multipart / form-data来保持一致性