2017-08-29 88 views
6

Mobil uygulamadan bir görüntü dosyası yüklemeye çalışıyorum (yerel olarak tepki vermek için yazılmış ve şimdi iOS'ta çalışıyor).NodeJS/Restify: API'ye dosya yükleme işlemini nasıl yapabilirim?

Dosya, aşağıda gösterilen REST API'ma gönderilir. başlıkları doğru gönderilmektedir rağmen, her zaman boş bir nesnedir olarak

  1. Ben req.body alamadım: Ben buna iki sorunların var.
  2. Alınan dosyayı gridfs-stream aracılığıyla DB (GridFS) dosyasına yazmak istiyorum, ancak bu kodu nereye koyacağımı anlamıyorum.

    başlıkları:

API

const restify = require('restify') 
const winston = require('winston') 
const bunyanWinston = require('bunyan-winston-adapter') 
const mongoose = require('mongoose') 
const Grid = require('gridfs-stream') 
const config = require('../config') 

// Configure mongoose to work with javascript promises 
mongoose.Promise = global.Promise 

// Setting up server 
const server = restify.createServer({ 
    name: config.name, 
    version: config.version, 
    log: bunyanWinston.createAdapter(log) 
}) 

server.use(restify.plugins.multipartBodyParser()) 

server.listen(config.port,() => { 
    mongoose.connection.on('open', (err) => { 
    server.post('/upload', (req, res, next) => { 
     console.log(req.headers) // <- returns headers as expected 

     /* Problem 1 */ 
     console.log(req.body) // <- is empty object (unexpected) 
     res.send(200, { message: 'successful upload' }) 
     res.end() 
    }) 
    }) 

    global.db = mongoose.connect(config.db.uri, { useMongoClient: true }) 

    /* Problem 2: The recieved file should be stored to DB via `gridfs-stream` */ 
    // I think this is the wrong place for this line... 
    var gfs = Grid(global.db, mongoose.mongo) 
}) 

hatası bulmaya çalıştım, ama onu bulamadık, işte benim API olsun verilerdir

{ 
    host: 'localhost:3000', 
    'content-type': 'multipart/form-data; boundary=pUqK6oKvY65OfhaQ3h01xWg0j4ajlanAA_e3MXVSna4F8kbg-zT0V3-PeJQm1QZ2ymcmUM', 
    'user-agent': 'User/1 CFNetwork/808.2.16 Darwin/15.6.0', 
    connection: 'keep-alive', 
    accept: '*/*', 
    'accept-language': 'en-us', 
    'accept-encoding': 'gzip, deflate', 
    'content-length': '315196' 
} 

gövde

{ } 

Neden body boş mu?


Yerli dosya ben API dosyayı gönderiyorum nasıl budur

karşıya yanıt verin.

{ 
    fileSize: 314945, 
    origURL: 'assets-library://asset/asset.JPG?id=106E99A1-4F6A-45A2-B320-B0AD4A8E8473&ext=JPG', 
    longitude: -122.80317833333334, 
    fileName: 'IMG_0001.JPG', 
    height: 2848, 
    width: 4288, 
    latitude: 38.0374445, 
    timestamp: '2011-03-13T00:17:25Z', 
    isVertical: false, 
    uri: 'file:///Users/User/Library/Developer/CoreSimulator/Devices/D3FEFFA8-7446-42AB-BC7E-B6EB88DDA840/data/Containers/Data/Application/17CE8C0A-B781-4E56-9347-857E74055119/Documents/images/69C2F27F-9EEE-4611-853E-FC7FF6E5C373.jpg' 
} 

yapılandırma bence

'http://localhost:3000/upload', 
{ 
    method: 'post', 
    body: 
    { 
     _parts: 
     [ 
      [ 'picture', 
      { uri: 'file:///Users/User/Library/Developer/CoreSimulator/Devices/D3FEFFA8-7446-42AB-BC7E-B6EB88DDA840/data/Containers/Data/Application/17CE8C0A-B781-4E56-9347-857E74055119/Documents/images/69C2F27F-9EEE-4611-853E-FC7FF6E5C373.jpg', 
       name: 'selfie.jpg', 
       type: 'image/jpg' } 
      ] 
     ] 
    } 
} 

data (config vücut olarak göndermek gereken)

async function upload (photo) { 
    console.log('photo', photo); // OUTPUT SHOWN BELOW 
    if (photo.uri) { 
    // Create the form data object 
    var data = new FormData() 
    data.append('picture', { uri: photo.uri, name: 'selfie.jpg', type: 'image/jpg' }) 

    // Create the config object for the POST 
    const config = { 
     method: 'POST', 
     headers: { 
     'Accept': 'application/json' 
     }, 
     body: data 
    } 
    console.log('config', config); // OUTPUT SHOWN BELOW 

    fetchProgress('http://localhost:3000/upload', { 
     method: 'post', 
     body: data 
    }, (progressEvent) => { 
     const progress = progressEvent.loaded/progressEvent.total 
     console.log(progress) 
    }).then((res) => console.log(res), (err) => console.log(err)) 
    } 
} 

const fetchProgress = (url, opts = {}, onProgress) => { 
    console.log(url, opts) 
    return new Promise((resolve, reject) => { 
    var xhr = new XMLHttpRequest() 
    xhr.open(opts.method || 'get', url) 
    for (var k in opts.headers || {}) { 
     xhr.setRequestHeader(k, opts.headers[k]) 
    } 
    xhr.onload = e => resolve(e.target) 
    xhr.onerror = reject 
    if (xhr.upload && onProgress) { 
     xhr.upload.onprogress = onProgress // event.loaded/event.total * 100 ; //event.lengthComputable 
    } 
    xhr.send(opts.body) 
    }) 
} 

fotoğraf: Ben de bazı değişkenlerin içeriğini göstermek yanlış biçim var. Neden bir dizide bir dizi var? Sen base64 gerek

+0

değil doğrudan bir cevap ama saf javascript yeterli performansı olacağını düşünüyorum, bu yüzden yükleme vardır tepki yerli getirme-blob kullanarak önermek geri bildirim de. – eden

+0

@Eden: Belki bir kod gönderebilirsiniz, yukarıdaki kodun nasıl tepki-native-fetch-blob ile yapılması gerektiği ...? – user3142695

+0

emin, bana birkaç dakika ver. – eden

cevap

-3

görüntüyü kodlamak ve ardından

+0

Lütfen bana bir kod örneği gösterebilir misiniz? – user3142695

+0

Bu bağlantının sizin için yararlı olabilecek birçok örneği olduğunu düşünüyorum - https://github.com/react-community/react-native-image-picker/issues/61 –

+1

Base64encode kullanmak zorunda değilsiniz: https: //snowball.digital/Blog/Uploading-Images-in-React-Native – user3142695

1

Aşağıdaki örnek react-native-fetch-blob dosyasında yerel kısmını tepki ve Express ile Nodejs kullanır (uygulama/json ayarlı başlık Content-Type ile) json olarak vücuda göndermek ve sunucu tarafında form ayrıştırmak için Formidable.

Let ilk kullanıcı bir fotoğraf ya da video yükledi olup olmadığını belirledikten sonra dosya yüklemek: Dosya almak, Benzer

RNFetchBlob.fetch(
    'POST', 
    Constants.UPLOAD_URL + '/upload', 
    { 
    'Content-Type': 'multipart/form-data' 
    }, 
    [ 
    { 
     name: this.state.photoURL ? 'image' : 'video', 
     filename: 'avatar-foo.png', 
     type: 'image/foo', 
     data: RNFetchBlob.wrap(dataPath) 
    }, 
    // elements without property `filename` will be sent as plain text 
    { name: 'email', data: this.props.email }, 
    { name: 'title', data: this.state.text } 
    ] 
) 
    // listen to upload progress event 
    .uploadProgress((written, total) => { 
    console.log('uploaded', written/total); 
    this.setState({ uploadProgress: written/total }); 
    }) 
    // listen to download progress event 
    .progress((received, total) => { 
    console.log('progress', received/total); 
    }) 
    .then(res => { 
    console.log(res.data); // we have the response of the server 
    this.props.navigation.goBack(); 
    }) 
    .catch(err => { 
    console.log(err); 
    }); 
}; 

ve buna göre veri yüklemek:

exports.upload = (req, res) => { 
    var form = new formidable.IncomingForm(); 
    let data = { 
    email: '', 
    title: '', 
    photoURL: '', 
    videoURL: '', 
    }; 

    // specify that we want to allow the user to upload multiple files in a single request 
    form.multiples = true; 
    // store all uploads in the /uploads directory 
    form.uploadDir = path.join(__dirname, '../../uploads'); 

    form.on('file', (field, file) => { 
    let suffix = field === 'image' ? '.png' : '.mp4'; 
    let timestamp = new Date().getTime().toString(); 

    fs.rename(file.path, path.join(form.uploadDir, timestamp + suffix)); //save file with timestamp. 

    data[field === 'image' ? 'photoURL' : 'videoURL'] = timestamp + suffix; 
    }); 
    form.on('field', (name, value) => { 
    data[name] = value; 
    }); 
    form.on('error', err => { 
    console.log('An error has occured: \n ' + err); 
    }); 
    form.on('end',() => { 
    // now we have a data object with fields updated. 
    }); 
    form.parse(req); 
}; 

Ve denetleyici işlevini kullanın:

let route = express.Router(); 
// other controller functions... 
route.post('/upload', uploadController.upload); 
app.use(route); 

Kodda yer alan yorumları okuduğunuzdan emin olun. Datapath, react-native-image-picker kullanıldıktan sonra oluşturulan yolun (base64 dizesi değil) yoludur. Yükleme işlemini göstermek için react-native-progress'u kullanabilirsiniz.

ara üzerinden daha fazla referans için reaksiyona yerli getirme-blob'un MultiPartForm veri bölümü: İlk olarak

: https://github.com/wkh237/react-native-fetch-blob#multipartform-data-example-post-form-data-with-file-and-data

+0

Dosyayı almayı ve dosyayı herhangi bir dizinde saklamaksızın DB'ye gridfs-stream yoluyla doğrudan depolamayı düşündüm. mümkün.? – user3142695

+0

Evet neden olmasın. Arka uç tasarımı hakkında. Yerel olarak tepki vermek için, veri yükleme yöntemi doğru yoldur. – eden

+0

Çözüm dosyasında 'yol 'nedir? – user3142695

0

bir ara katman yazma co-busboy düğüm modülünü kullanarak, bu koa için bir örnektir

npm i co-busboy -S veya yarn add co-busboy

: Eğer npm veya yarn tarafından co-busboy yüklemeniz gerekir

// upload.js 
 
var parse = require('co-busboy') 
 
var fs = require('fs') 
 
var path = require('path') 
 
var upload = function * (next) { 
 
    var parts = parse(this, { 
 
    autoFields: true 
 
    }) 
 
    while(var part = yield parts) { 
 
    part.pipe(fs.createReadStream(path.join('uploadPath', part.filename))) 
 
    } 
 
    yield next 
 
} 
 

 
module.exports =() => upload 
 

 

 
// app.js 
 

 
var upload = require('upload') 
 
app.use(upload())

Referans:

co-busboy