Android request error... How to use request in store.js for android?

Using the last framework7 version 7.0 I tried many times to make a request inside the store.js but I end with errors in android

in the store.js I add this line at the top

import { createStore, getDevice, request} from 'framework7';

then I can use the request that works in IOS perfectly! but in android I receive many errors so I have to call the api using xhr XMLHttpRequest and works but I want both to use the same call.

I am using Android 11, 12 version with Cordova android 11 installed version

cordova platform add [email protected]

this is the request

        request({
          headers: {
            'Content-Type': 'application/json',
          },
          url: https://....,
          dataType: 'json',
          async: true,
          method: 'POST',
          data: JSON.stringify(data),
          cache: false,
          crossDomain: true,
        })
        .then((res) => {

          console.log( {all_products: res.data});

        }).catch(function (err) {

          if (retries > 0 && retryCodes.includes(status)) {

            setTimeout(() => {

              console.log("retrying: getting products... retries left... " + retries);
              resolve(store.dispatch('getProducts', {
                $f7, $,
                retries: retries - 1,
                backoff: backoff * 2
              }));

            }, 500);

          } else {
              ...
          }

        })

this works perfectly in iOS but in android device I get this error:

 POST https://.../v3/products 502
index.eb6287a6.js:176 Error
...    at XMLHttpRequest.f.onload (index.eb6287a6.js:24)

even if I use $f7.request.post for android the same error

 POST https://.../v3/products 502
index.eb6287a6.js:176 Error
...    at XMLHttpRequest.f.onload (index.eb6287a6.js:24)

any ideas why in android it does not work the same request as in iOS?
is there any fix for this?
thanks

it seems like you have this issue for years now.
how come you never fixed it?

it doesn’t really matter from where you call request,
since your code gets compiled/build to a single file anyway.
f7-request itself use XMLHttpRequest (from v8 it will be replaced to fetch),
so it’s really weird your app behavior

it’s hard to say what’s going on without seeing your full code, especially when it comes to cordova.

i can only guess that you messed with config.xml or something is wrong with your server-certificate,
usually/lately android is more restrictive when it come to server-calls.

my suggestion:
create a brand new project using f7-cli,
and don’t change anything (i mean it, just don’t)

the only thing you should do is adding this line to the end of app.js:

app.request
  .json('https://jsonplaceholder.typicode.com/todos/1')
  .then(r => r.data)
  .then(d => app.dialog.alert(d.title))

or this line:

app.request
  .post('https://jsonplaceholder.typicode.com/posts')
  .then(() => app.dialog.alert('done'))

or this:

app.request
  .post('https://jsonplaceholder.typicode.com/posts',{ foo: 'bar' },'json')
  .then(r => r.data)
  .then(d => app.dialog.alert(d.foo))

if you didn’t change anything other then the above code, and the issue still exists,
then i don’t know what to say.

1 Like

in case you wondering why those 3 different lines of code:
it’s just to cover all possibilities (when you will change the url to your server)
maybe your server is not configured well

1 Like

I updated to the latest framework v7 and my requests calls are basically inside my store.js, I used the $f7 there instead of app to make the request calls because app.request does not work properly and I receive all the time undefined there so I pass $7 instead and works.

In general for Android all request to my server using request fails all the time but using Xhr requests works without any issues.

In iOs the request calls works without any issue, and Xhr requests works with any issues in iOs.

It is Android the issue with requests calls using request or app.request too, I also put inside config.xml for android platform to avoid deal with restrictions that android 11, 12 has but this error still persists since a long time on my side.

I used this code inside my config.xml

<preference name="AndroidInsecureFileModeEnabled" value="true" />

Question:
what you mean with:

///the only thing you should do is adding this line to the end of app.js:

why inside app.js and not inside my store.js where all actions are?

In my case I have this in my store.js inside actions:

getProducts({ state }, {$f7, $, retries, backoff}) {
...
<here my request call>

this is in my home script

export default (props, {
    $,
    $f7,
    $f7router,
    $update,
    $on,
    $onBeforeMount,
    $onMounted,
    $onBeforeUpdate,
    $onUpdated,
    $onBeforeUnmount,
    $onUnmounted,
    $store,
  }) => {

    const loadProducts = () => {
      $store.dispatch('getProducts, {$f7, $, retries: 3, backoff: 300});
    };

In my view

 <button style="text-transform:none" @click="${loadProducts}" class="col button button-large color-black button-outline button-round">Request Products test</button>

so what you mean with

///the only thing you should do is adding this line to the end of app.js:

adding which line? the requests?

have you tried to run app.requests inside store.js? app is undefined for me all the time so I use $f7…

I still do not understand why Android (any version) it is the issue when using request calls! but with iOS everything works perfectly all the time!

any clues?
thanks

first of all i’m sorry if i sound a little bit aggressive (that’s my bad english).

now, before we even get into “store” or “f7” or “app” or “you name it”,
you need to fix your issue with android.

“request” works for all of us (can’t say how many, probably tens of thousands of us),
and it works in both ios and android,
so it’s really strange that you are the only one who can’t make it (for years now).

it’s even more stranger that pure-XMLHttpRequest works for you and “request” not,
since Framework7.request itself use internally XMLHttpRequest (from V8 it will be “fetch”)

again, i need to see your full project to understand what’s going on.
i can only guess that you messed with config.xml or something is wrong with your server/cert.

so let’s try to fix it:

  • create a new project using f7-cli
  • do not change config.xml (leave it “as it is”)
  • do not add your real code to the project (leave it “as it is”)
  • just add this line to app.js (right after const app = new Framework7(params)):
app.request
  .post('https://jsonplaceholder.typicode.com/posts',{ foo: 'bar' },'json')
  .then(r => r.data)
  .then(d => app.dialog.alert(d.foo))
  • build for android
  • test it on real device
  • it must works for you, because it works for all of us.

now, do the same thing again, but this time change the url to your server:

app.request
  .post('your-server',{ foo: 'bar' },'json')
  .then(r => r.data)
  .then(d => app.dialog.alert('done'))
  .catch(e => app.dialog.alert('err'))

if you get an error now, it means that something is wrong with your server/cert.

1 Like

request in store (using core + vite-js)
here => nifty-worker-6fyud7

Ok I will do that and get back to you during the day or tomorrow thanks for the tip so I see what is the problem with Android my server or my request code from client side.

I will use that url for the 1 test

https://jsonplaceholder.typicode.com/posts

By the way I use core + vite.js as well!

thanks keep you updated!

Hi I tried the method using the url for request that you sent me and works in iOS and Android with short method app.request.post but in my case I need to pass more parameters so I need to use app.request, in this case the { foo: ‘bar’ } object data is not being passed to Android when using app.request but with app.request.post they data object is received by the server not empty.

I tried with my request urls and same thing,

Remember in my case I cannot use app.request.post because I need to pass more information about header and data with the request so here my request with app.request:

      var data = {
        "bucket_identifiers": [
            "Favorites",
            "LastToday",
            "Tomorrow",
        ]
      };

        request({ 
          url:'https://...tester/v1',
          headers: {
            'Content-Type': 'application/json',
          },
          statusCode: {
            404: function (xhr) {
              console.log('404');
            }
          },
          method: 'POST',
          data: JSON.stringify(data), 
          cache: false,
          dataType: 'json'  
        })
        .then((r) => {
          console.log({r: r.data});
          //r.data;
        })
        .then((d) => {
          $f7.dialog.alert('done')
        })
        .catch((e) => {
          $f7.dialog.alert('err')
          $f7.dialog.alert(e);
          console.log(e);
        });

reply from iOS

reply from Android

As you see in Android the data object bucket_identifiers is not being received by the server because it is empty but in iOS they are received and not empty !

I think the problem comes from this when using app.request! using xhr requests instead of app.request with Android the data object is received and not empty!

Maybe it is a bug in the app.request with post to pass object data?

Can you use app.request instead of app.request.post and pass an object data and try by yourself this?

by the way this is on my server for this test, very simple, I am using lambda with API Gateway in aws.

var express = require('express')
var bodyParser = require('body-parser')
var awsServerlessExpressMiddleware = require('aws-serverless-express/middleware')
....

var app = express()
app.use(bodyParser.json())
app.use(awsServerlessExpressMiddleware.eventContext())

/****************************
* post method *
****************************/
app.post('/tester/v1', function(req, res) {

  const {
    bucket_identifiers
  } = req.body; //body is empty with android!
  
  res.status(200).json({
    success: 'post tester call succeed!', 
    url: req.url, 
    bucket_identifiers: bucket_identifiers
  });

});

thanks!

I tried many things and same issue with Android finally I moved from app.request to fetch and now it works with both Android and iOS!

Final answer for me:

I think the problem comes form the use of app.request with POST not sending data object to the server with Android but with iOS works perfectly but not for Android! It is not a server side problem it is a request problem!

if I use fetch in iOS and Android works perfectly

        var myHeaders = new Headers();
        myHeaders.append("Content-Type", "application/json");
        
        var raw = JSON.stringify({
          "bucket_identifiers": [
            "Favorites",
            "LastToday",
            "Tomorrow",
          ]
        });
                
        fetch("https://.../tester/v1", 
        {
          method: 'POST',
          headers: myHeaders,
          body: raw,
          redirect: 'follow'
        })
          .then(response => response.json())
          .then(result => console.log(result))
          .catch(error => console.log('error', error));

reply in android using fetch:

and in iOS using fetch same request:

So here my final thought! I think request has a big bug! never worked with Android with POST request and sending data and it seems the problem still persists at least for me! or nobody has used request with POST and data object yet?

I will move to fetch I think it is the final solution! problem solved!

finally.

in a few days (or weeks) V8 will be released, and we all gonna use fetch.

anyway fetch is better then xhr

there is no bug, you just doing it wrong
here:

const data = {
  key: 'value',
  bucket_identifiers: ['Favorites','LastToday','Tomorrow'] 
};
app.request({
  url: 'https://jsonplaceholder.typicode.com/posts',
  method: 'POST',
  dataType: 'json',
  processData: false,
  data: JSON.stringify(data),
  contentType: 'application/json',
  success: (d) => console.log(d),
  error: (e) => console.log(e)
});

return on success:

{
  id: 101,
  key: 'value',
  bucket_identifiers: ['Favorites','LastToday','Tomorrow'] 
}

just to clarify…
fetch won’t make your request faster (how fast is it, it depends only on your server).
the only diff is in the parsing of the return content:

  • fetch use promise => (more efficient)
  • xhr, no promise => (less efficient)

but, since f7.request make the xhr in promise, there is no real difference.

can you explain where is the wrong thing?

contentType: ‘application/json’?
processData: false?

I will make some tests now to get into a conclusion!
Get back to you soon!

I think the error comes from “Content Type” not declared in the request as contentType: ‘application/json’ right?

I tried my request with “Content-Type”: “application/json” in the headers and I see in Android the only thing that works is adding also in the request contentType: ‘application/json’.

In iOS never had this problem even if contentType: ‘application/json’ was not included in the request and only in the headers but Android I think it is very picky!

so

headers: {
  "Content-Type": "application/json"
},

must include also for Android

contentType: 'application/json',

This is what you meant above when you say there is no bug, you just doing it wrong?

This code below now works for me in Android and iOS!

 $f7.request({
          url: '.../tester/v1',
          headers: {
            "Authorization": "Bearer" + token,
            "Content-Type": "application/json"
          },
          method: 'POST',
          dataType: 'json',
          processData: false,
          data: JSON.stringify(data),
          contentType: 'application/json',
          success: (d) => console.log(d),
          error: (e) => console.log(e)
        });

first of all, i’m glad that you finally made it (i really am).

now,
my english is very bad, and it would take a very long answer,
with a lot of replies and clarification to explain what is really going on,
and where you messed it up.

the easiest way to do it:
go to => framework7/request.js at master · framework7io/framework7 · GitHub
and read it carefully, it’s pretty much self-explained.

if you didn’t get it, then write me back and i’ll try my best to explain it.

and no, there is no bug.

and don’t take it personally,
but sometimes, while reading this forum,
i have a feeling that a BUG is actually an abbreviation/acronym for:
“i’m doing it wrong, so let’s just blame vladimir”

In my case the solution was that for Android because iOS always worked fine with or without declaring contentType in the request!

I thought it was a bug since “Content-Type”: “application/json” was declared in the headers for both iOS and Android but as you can see using fetch you do not have to pass it in the request but only in the headers to work with Android!

I do speak Spanish too in case you do too you can reply me in Spanish :slight_smile:
thanks for being there and help to find a solution!

i don’t speak spanish.
i live in italy (but i’m not italian, my italian is better then english, but not so good)
even with my mother-lang(hebrew) i don’t speak it very well,
that’s why i usally respond with code.

so let’s try with code:

first read this spec => RFC 9110 - HTTP Semantics

i’ll highlight the important stuff from it:

Although Content-Type is defined as a singleton field,
it is sometimes incorrectly generated multiple times,
resulting in a combined field value that appears to be a list.
Recipients often attempt to handle this error by using
the last syntactically valid member of the list,
leading to potential interoperability and security issues
if different implementations have different error handling behaviors.

in short:
Content-Type must have a single value.
if it’s not, then weird things may happen.
and this is actually what’s happened with your code.

now, go to => [Request] peaceful-heyrovsky-7o4q7z

output:
ref[0] => KO => content-type: application/x-www-form-urlencoded
ref[1] => KO => content-type: application/x-www-form-urlencoded, application/json
ref[2] => KO => content-type: application/json, application/json
ref[3] => OK => content-type: application/json

ref[3] is OK
so this is the correct way for making post-json

app.request({
  url: url,
  method: 'POST',
  dataType: 'json',
  processData: false,
  data: JSON.stringify(data),
  contentType: 'application/json',
  headers: { 'Authorization': 'Bearer{token}' }
});

i didn’t test it on ios (i don’t have an ios device…)
and if you did test it and you see that ref[1] and ref[2] are OK
i assume (only if you really test it) that ios “fix it” for you,
and send only the last value in “content-type”,
which make ref[1] and ref[2] OK (it shouldn’t be ok, but if you say so, i believe you).

in android i did test it, and android keep it “as it is”
which is why ref[1] and ref[2] are KO

btw, if i understood right, ref[2] works for you on ios (and ref[1] not),
even if it shouldn’t (i think it must be {ref[2] == KO} also on ios, but i don’t have an ios device).

my ws is apache and i never use yours,
so here 2 guesses for {ref[2] == OK} on ios:

  • ios send only the first value in ‘content-type’
  • your ws handle only the first value in ‘content-type’

I will test it later today and send you feedback I do also speak Italian! :slight_smile:

I tried many things and same issue with Android finally I moved from app.request to fetch and now it works with both Android and iOS!

1 Like