NativeScript / nativescript-angular

Integrating NativeScript with Angular
http://docs.nativescript.org/angular/tutorial/ng-chapter-0
Apache License 2.0
1.22k stars 241 forks source link

RE: Nativescript plugin background-http produces issue "error during upload" #770

Closed samliaw closed 7 years ago

samliaw commented 7 years ago

Hi, I am testing nativescript-background-http to test upload a picture file to server.

I test using physical mobile device. Below is the coding file ==================================start of a.component.ts================================

import { Component } from '@angular/core';
import * as bghttp from "nativescript-background-http";
import * as fs from "file-system";

@Component({
    moduleId: module.id,
    template: "<Button text='Upload File' (tap)='uploadFile()'></Button>"
})
export class aComponent {
    public session = bghttp.session("image-upload");

    uploadFile() {
        const filepath: string = "/data/user/0/org.nativescript.Groceries/cache/img_by_sj_1493113215112.jpg";
        const filename: string = "img_by_sj_1493113215112.jpg";

        let fileExist = fs.File.exists(filepath);
        // confirm file exists.
        console.log("file exist? ", fileExist);
        let request = {
            url: "http://it-enable.net:9191/file",
            method: "post",
            headers: {
                "Content-Type": "application/octet-stream",
                "File-name": filename
            },
            description: "{ 'uploading': '" + filename + "' }"
        }

        let task = this.session.uploadFile(filepath, request);
        task.on("progress", this.logEvent);
        task.on("error", this.logEvent);
        task.on("complete", this.logEvent);

    }
    logEvent(e) {
        console.dump(e);
    }
}

==================================end of a.component.ts================================

==================================start of package.json================================

{
  "name": "typescript anuglar redux",
  "version": "0.0.1",
  "description": "NativeScript Application",
  "license": "SEE LICENSE IN <your-license-filename>",
  "readme": "NativeScript Application",
  "repository": "<fill-your-repository-here>",
  "nativescript": {
    "id": "org.nativescript.Groceries",
    "tns-android": {
      "version": "2.5.0"
    }
  },
  "dependencies": {
    "@angular/common": "2.4.3",
    "@angular/compiler": "2.4.3",
    "@angular/core": "2.4.3",
    "@angular/forms": "2.4.3",
    "@angular/http": "2.4.3",
    "@angular/platform-browser": "2.4.3",
    "@angular/platform-browser-dynamic": "2.4.3",
    "@angular/router": "3.4.3",
    "@ngrx/core": "^1.2.0",
    "@ngrx/effects": "^2.0.2",
    "@ngrx/store": "^2.2.1",
    "email-validator": "^1.0.7",
    "file-system": "^2.2.2",
    "nativescript-angular": "1.4.0",
    "nativescript-background-http": "^2.5.1",
    "nativescript-camera": "0.0.8",
    "nativescript-drawingpad": "^1.1.2",
    "nativescript-social-share": "^1.3.2",
    "nativescript-telerik-ui-pro": "file:F:\\NativeScript\\Packages\\nativescript-ui-pro.tgz",
    "nativescript-theme-core": "~1.0.2",
    "ramda": "^0.23.0",
    "reflect-metadata": "~0.1.8",
    "rxjs": "~5.0.1",
    "tns-core-modules": "2.5.0"
  },
  "devDependencies": {
    "babel-traverse": "6.4.5",
    "babel-types": "6.4.5",
    "babylon": "6.4.5",
    "eslint": "^3.19.0",
    "lazy": "1.0.11",
    "nativescript-dev-android-snapshot": "^0.*.*",
    "nativescript-dev-typescript": "^0.3.5",
    "typescript": "~2.1.0",
    "zone.js": "~0.7.2"
  }
}

==================================end of package.json================================

I am using the node.js restify to accept the file. I have tested using Postman and it works file. The code of the restify is as below ==================================start of restify index.js================================

var restify = require('restify');
var fs = require('fs');
var os = require('os');
var server = restify.createServer({
    name: 'software-manufacture-backend-file',
    version: '0.1.0'
});
var Throttle = require("stream-throttle").Throttle;
var outDir = "/mnt/diskc/p/restify-file/uploads/";
server.use(restify.acceptParser(server.acceptable));
server.use(restify.CORS());
server.use(restify.queryParser());
server.use(restify.gzipResponse());
server.use(function (req, res, next) {
    console.log('it reach the restify-file api without body parser');
    return next();
});
server.get('/test', function (req, res, next) {
    res.send(200, 'SUCCESS');
    res.end;
    return next();
});
server.post('/file', function (req, res, next) {
    console.log(req.params);
    var fileName = req.headers["file-name"];
    console.log("req.headers are", req.headers);
    var logger = console;
    logger.log(req.method + "Request! Content-Length: " + req.headers["content-length"] + ", file-name: " + fileName);
    logger.dir(req.headers);
    var out = outDir + "upload-" + new Date().getTime() + "-" + fileName;
    logger.log("Output in: " + out);
    var total = req.headers["content-length"];
    var current = 0;
    var shouldFail = req.headers["should-fail"];
    req.pipe(new Throttle({ rate: 1024 * 2048 })).pipe(fs.createWriteStream(out, { flags: 'w', encoding: null, fd: null, mode: 0666 }));
    req.on('data', function (chunk) {
        current += chunk.length;
        if (shouldFail && (current / total > 0.25)) {
            logger.log("Error ");
            var body = "Denied!";
            res.send(408, "Die!", { "Content-Type": "text/plain", "Content-Length": body.length, "Connection": "close" });
            res.end();
            shouldFail = false;
            logger.log("Terminated with error: [" + out + "]: " + current + " / " + total + "  " +
                Math.floor(100 * current / total) + "%");
        }
        else {
            logger.log("Data [" + out + "]: " + current + " / " + total + "  " + Math.floor(100 * current / total) + "%");
        }
    });
    req.on('end', function () {
        logger.log("Done (" + out + ")");
        var body = "Upload complete!";
        res.send(200, "Done!", { "Content-Type": "text/plain", "Content-Length": body.length });
        res.end();
    });
    req.on('error', function (e) {
        logger.log('it reach the file received error!');
        logger.log(e);
    });
});
process.on('uncaughtException', function (err) {
    console.log('uncaught Exception is ', err);
});
server.listen(9191, function () {
    console.log('%s listening at %s', server.name, server.url);
});

==================================end of restify index================================

==================================start of restify packson.json================================

{
  "name": "restify-file",
  "version": "0.0.1",
  "description": "It only accepts files",
  "main": "index.js",
  "author": "Sam Liaw <samliaw@it-enable.net>",
  "license": "MIT",
  "dependencies": {
    "ramda": "^0.23.0",
    "restify": "^4.3.0",
    "stream-throttle": "^0.1.3"
  }
}

==================================endof restify packson.json================================

When I use the Postman, I provide the following attirbutes Method: Post URL: http://it-enable.net:9191/file Header: {"Content-Type":"application/octet-stream"} Attached a picture file.

If the file is uploaded successfully, I can see the response of "Done!".

When I run the project in physical mobile device, I hit the error "error during upload." When I look at backend restify, I find that the nativescript-background-http hits error before it sends the file to backend restify. This is because the backend restify doesn't inidicate it has receives any file.

I do test this whole afternoon but to no vail. I copy the source code that people have claim successful executing but it doesn't work for me. There is no detail error code so I am not able to figure what is wrong.

Any suggestion or method is welcomed.

NickIliev commented 7 years ago

This issue was moved to NativeScript/nativescript-background-http#61

samliaw commented 7 years ago

Hi,

I spend some more time to debug and finally confirm what cause the issue. Please look at the code in the component. I simply change the lowercase "post" to all uppercase "POST" and it works perfectly.

hopefully this will help other people who face similar issue like me.

    let request = {
        url: "http://it-enable.net:9191/file",
        method: "post", //<----- change post to POST solve the issue
        headers: {
            "Content-Type": "application/octet-stream",
            "File-name": filename
        },
        description: "{ 'uploading': '" + filename + "' }"
    }