Nativescript-angular: Wrong Response.text() behavior

Created on 17 Jul 2016  路  20Comments  路  Source: NativeScript/nativescript-angular

Trying to get a simple string from a REST-API using the Angular's Http.get(), but having an unexpected trouble while trying to get the Response's body, using Response.text():
Expected response:


Actual response:

<66363332 37303033 62306262 38646366 61356236 62353230 37616535 35613762>

I assume the problem is that the response from the server is not a JSON, nor HTML, but a plain text string and looks like it is stored internally using NSData, and there might be something wrong during string extraction from NSData.

versions:
Angular 2.0.0-rc.4
TNS-core: 2.1.1
NativeScript-Angular 0.2.1

Most helpful comment

@chiefmc
After some investigation: What you are seeing is actually toString-ed NSData of the response.
There is a pending fix: NativeScript/NativeScript#2487

There is a workaround(not very pretty though). Get the response body and call IOS native API to convert it to string:

import {Http, Headers, Response} from "@angular/http";
import * as platform from "platform";

// ...

declare var NSString: any;
function getResponseText(response: Response): string {
    if (platform.isIOS) {
        const nsData = (<any>response)._body;
        return NSString.alloc().initWithDataEncoding(nsData, 4).toString();
    }
    return response.text();
}

// ...

this._http.get("https://breakouttrampoliningwebservices.azurewebsites.net/test/guid")
    .subscribe(response => {
        console.log("TEXT: " + getResponseText(response));
    });

All 20 comments

@chiefmc Are you using NS_HTTP_PROVIDERS or just HTTP_PROVIDERS as mentioned here: https://github.com/NativeScript/nativescript-angular/wiki/Http

Also if it's a public api you wouldn't mind sharing, I could take a look at the call/response to help investigate as well.

Thanks for prompt response!

Yes, I'm using the NS_HTTP_PROVIDERS, but unfortunately the API is proprietary.

Any further ideas what to look for?

Thanks!

Check that the endpoint returns the content as: "text/plain"

what's the content type of the result ? last time I checked (many months ago) it was auto-serializing based on that rather than treating the content differently based on the action .text() .json() etc. ie getting a JSON-result and then using .text() just ran .toString() on what was serialized (giving '[object] [object]') rather than giving the response content as text. Has that all changed? it was 4-6 months ago.

API actually returns text/html.

Here're the response headers:

Cache-Control:no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Connection:close
Content-Encoding:gzip
Content-Length:52
Content-Type:text/html; charset=utf-8
Date:Sun, 17 Jul 2016 09:27:18 GMT
Expires:Thu, 19 Nov 1981 08:52:00 GMT
Pragma:no-cache
Server:nginx/1.8.1
Strict-Transport-Security:max-age=31536000; includeSubdomains;
Vary:Accept-Encoding
X-Powered-By:PHP/5.4.45

Seems that auto-serializer makes wrong assumptions.

Just did a test on a dev server: changed the response headers to text/plain. The result is the same - no luck

Just done a quick test and all came back as expected in RC3
Content-Type: text/plain; charset=utf-8

JS: expect: Hello world! Time is: {0}
JS: Hello world! Time is: 7/17/2016 3:38:04 PM
JS: f70181cb-1e8a-4fe8-b2dc-91ed97a2aa30
JS: 636043666847681798
        this.http.get("http://breakouttrampoliningwebservices.azurewebsites.net/test/string")
            .map(e=> e.text())
            .subscribe(e => {
                console.log("expect: Hello world! Time is: {0}");

                console.log(e);
            }, (e) => {
                console.log(e);
            });
        this.http.get("http://breakouttrampoliningwebservices.azurewebsites.net/test/number")
            .map(e=> e.text())
            .subscribe(e => {
                console.log(e);
            }, (e) => {
                console.log(e);
            });
        this.http.get("http://breakouttrampoliningwebservices.azurewebsites.net/test/guid")
            .map(e=> e.text())
            .subscribe(e => {
                console.log(e);
            }, (e) => {
                console.log(e);
            });

Upgraded to RC4 ... and it still works.

Just replaced the endpoint with the one from your example:

        return this._http.get(
            "http://breakouttrampoliningwebservices.azurewebsites.net/test/guid",
            { headers: apiRequestHeaderHelper() }
        )
            .do(data => {
                Config.apiAuthToken = data.text();
                console.log("Raw response: " + JSON.stringify(data));
                console.log("received auth token: " + Config.apiAuthToken);
            })
            .catch(this.handleError);

and the result didn't change, response I get:
received auth token: <33336563 39643830 2d353236 642d3465 36322d38 6435652d 32393637 37663538 36303330>

Also tried on both 2.0.0-rc.3 and rc.4

Am I doing something wrong?

Just tried other API method, which returns JSON and it works just fine. So it seems to be the problem with Response.text() transformation for plain text response.

if you don't include the headers do you get the same result?

I tried to confuse it a bit by adding:

let headers = new Headers();
        headers.append('Content-Type', 'application/json');
        headers.append('Accept', 'text/xml');
        var requestObtionsArgs : RequestOptionsArgs= { 
            headers: headers,
            withCredentials: true
        };

but all had the correct responses back.
Back to the providers as Natan was pointing to earlier. Are you using AuthHttp, Http or the NSHttp provider? Getting Http as a dependency should provide the NSHttp provider now if NS_HTTP_PROVIDERS is included in nativeScriptBootstrap or you may have setup it yourself (as I get bored waiting for the odd release) and include it in the providers at startup.:

var http = [
            HTTP_PROVIDERS,
            provide(XSRFStrategy, { useValue: new NSXSRFStrategy() }),
            provide(Http, { useFactory: (backend, options, nsFileSystem) => {
                return new NSHttp(backend, options, nsFileSystem);
            }, deps: [XHRBackend, RequestOptions, NSFileSystem]})        
        ];

Can you paste how your nativeScriptBootstrap method looks

Thanks for your response.

I'm using the NS_HTTP_PROVIDERS, but injecting it at an AppComponent level, not in main.ts. I've tried to move it to nativeScriptBootstrap, but result is the same.

Also tried to omit the headers param

Any thoughts will be greatly appreciated

I must mention, that the same code works perfectly in Android environment. So the problem most probably lies somewhere in-between NS and iOS

No ideas how to get around this problem? Anyone?

@chiefmc
After some investigation: What you are seeing is actually toString-ed NSData of the response.
There is a pending fix: NativeScript/NativeScript#2487

There is a workaround(not very pretty though). Get the response body and call IOS native API to convert it to string:

import {Http, Headers, Response} from "@angular/http";
import * as platform from "platform";

// ...

declare var NSString: any;
function getResponseText(response: Response): string {
    if (platform.isIOS) {
        const nsData = (<any>response)._body;
        return NSString.alloc().initWithDataEncoding(nsData, 4).toString();
    }
    return response.text();
}

// ...

this._http.get("https://breakouttrampoliningwebservices.azurewebsites.net/test/guid")
    .subscribe(response => {
        console.log("TEXT: " + getResponseText(response));
    });

Thanks, @vakrilov!

Subscribed to the pull request. Hopefully this fix will be released to public soon.

Meanwhile will be using initWithDataEncoding()

@chiefmc
The fix is live in the @next builds (you will have to include both tns-core-modules and nativescript-angular) in the package.json:

"nativescript-angular": "@next",
"tns-core-modules": "@next"

Also - make sure you switch to NS_HTTP_PROVIDERS.

@chiefmc @vakrilov do this instead in your package.json:

"nativescript-angular": "next",
"tns-core-modules": "next"

If you use @next, it will complain of unknown tag.

Cheers, guys!

It works now! Many thanks!

I've had the same problem with NativeScript 2.4 and NativeScript-angular 1.1.3 in my ios app with .text()

I've found a temporary work around by using getString from http. but i'm curious if anyone else is experiencing the same?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ignaciofuentes picture ignaciofuentes  路  31Comments

MartoYankov picture MartoYankov  路  73Comments

tsonevn picture tsonevn  路  27Comments

leocaseiro picture leocaseiro  路  31Comments

morzyns picture morzyns  路  39Comments