进行JSON调用的Android应用从服务器获取了意外数据,但相同的调用在浏览器中有效

我有一个Android应用,可以进行服务器调用并返回JSON。

如果我在浏览器中输入URL,服务器代码将返回正确的字符串。但这会在Java应用程序中创建异常(http和https服务器调用的不同问题)。

https://www.problemio.com/auth/mobile_login.php?login=test.name@gmail.com&password=130989

返回此字符串:

[{"user_id":"1601470","email":"test.name@gmail.com","first_name":"TestName","last_name":null}]

这是解析JSON但给出异常的Java调用:

@Override
protected void onPostExecute(String result) 
{

    try {
        dialog.dismiss();
    } catch (Exception ee) {
        // nothing
    }           

    if ( connectionError == true )
    {
        Toast.makeText(getapplicationContext(),"Please try again. Possible Internet connection error.",Toast.LENGTH_LONG).show();  
    }           

    if ( result != null && result.equals( "no_such_user") )
    {
        Toast.makeText(getapplicationContext(),"Your email and password do not match out records. Please try again or create and account.",Toast.LENGTH_LONG).show(); 

        //final TextView login_error = (TextView) findViewById(R.id.login_error);
    }
    else
    {
        Log.d( "CONNECTION*** ERRORS: ","ok 3 and result length: " + result.length()  );

        String firstName = null;
        String lastName = null;
        String email = null;
        String user_id = null;

        try
        {
            JSONArray obj = new JSONArray(result);
            JSONObject o = obj.getJSONObject(0);
            firstName = o.getString("first_name");
            lastName = o.getString("last_name");
            email = o.getString("email");
            user_id = o.getString("user_id");
        }
        catch ( Exception e )
        {
            Log.d( "JSON ERRORS: ","something happened ****" + e.getMessage() );
        }


        // 1) First,write to whatever local session file that the person is logged in
        // - I just really need user id and name and email. And store that.
        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences( 
                Loginactivity.this);

        if ( user_id != null && user_id.trim().length() > 0 && !user_id.trim().equals("null") )
        {
            prefs.edit()
            .putString("first_name",firstName)
            .putString("last_name",lastName)
            .putString("email",email)              
            .putString("user_id",user_id)
            .putBoolean("working",true)
            .commit();

            if ( user_id.equals("1"))
            {
                prefs.edit()
                .putString("community_subscription","1")
                .commit();
            }
        }
    }
}    
}

这是异常消息:

End of input at character 0 of

它看起来像字符串是0个字符长。

知道为什么会这样吗?在我将网站切换到https之前,此调用一直可以正常工作。

服务器也进行http呼叫。如果我将其更改为https,则会返回一整堆HTML,这很奇怪,因为我实际上并未将其发送回去。

这是我的doInBackground方法:

@Override
protected String doInBackground(String... theParams) 
{
    String myUrl = theParams[0];
    final String myEmail = theParams[1];
    final String myPassword = theParams[2];

    String charset = "UTF-8";           

    Authenticator.setDefault(new Authenticator()
    {
        @Override
        protected Passwordauthentication getPasswordauthentication() 
        {
            return new Passwordauthentication( myEmail,myPassword.toCharArray());
        }
    }); 

编辑

如果我的doInBackground方法位于

内部
public class DownloadWebPagetask extends AsyncTask<String,Void,String>   

服务器是否太慢而无法返回字符串,这就是为什么它变为空的原因?

它总是崩溃,结果字符串为空:

JSONArray obj = new JSONArray(result);

编辑2

这是完整的代码:

package com.problemio;

import java.io.InputStream;
import java.net.Authenticator;
import java.net.HttpURLConnection;
import java.net.Passwordauthentication;
import java.net.URL;
import java.net.URLEncoder;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import java.io.InputStreamReader;
import java.io.BufferedReader;

import org.json.JSONArray;
import org.json.JSONObject;

import com.flurry.android.FlurryAgent;

import utils.SendEmail;

import android.app.Dialog;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

public class Loginactivity extends Baseactivity 
{
    //private TextView textView;
    private Dialog dialog;

    public static final String REQUEST_METHOD = "GET";
    public static final int READ_TIMEOUT = 15000;
    public static final int CONNECTION_TIMEOUT = 15000;

    @Override
    public void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        FlurryAgent.onStartSession(this,"8CA5LTZ5M73EG8R35SXG");

        setContentView(R.layout.login);        

        //final TextView emailask = (TextView) findViewById(R.id.email_ask);

        // Show form for login_email
        final EditText loginEmail = (EditText) findViewById(R.id.login_email);  
        //String name = loginEmail.getText().toString();

        // Show field for password  
        final EditText password = (EditText) findViewById(R.id.password);
        //String text = password.getText().toString();
        //Log.d( "First parameters: ","Login email: " + loginEmail + " AND login password: " +  text);


        // Show button for submit
        Button submit = (Button)findViewById(R.id.submit);   

        submit.setOnClicklistener(new Button.OnClicklistener() 
        {  
           public void onClick(View v) 
           {
              String email = loginEmail.getText().toString();
              String pass = password.getText().toString();

               //Set the email pattern string
//            Pattern pattern = Pattern.compile(".+@.+\\.[a-z]+");
//            //Match the given string with the pattern
//            Matcher m = pattern.matcher(email);
//            //check whether match is found
//            boolean matchFound = m.matches();               

              // TODO: VALIDATE!!!
              if ( email == null || email.trim().length() < 2 )
              {
                  Toast.makeText(getapplicationContext(),"Please enter a valid email address.",Toast.LENGTH_LONG).show();                       
              }
              else
              if ( pass == null || pass.trim().length() < 2 )
              {
                  Toast.makeText(getapplicationContext(),"Please enter a correct password.",Toast.LENGTH_LONG).show();                          
              }
              else
              {
                 sendFeedback(pass,email); 
              }  
           }
        });        

        // Show button for submit
        Button forgot_password = (Button)findViewById(R.id.forgot_password);   

        forgot_password.setOnClicklistener(new Button.OnClicklistener() 
        {  
           public void onClick(View v) 
           {
              Toast.makeText(getapplicationContext(),"Please wait...",Toast.LENGTH_LONG).show();  

              Intent intent = new Intent(Loginactivity.this,ForgotPasswordactivity.class);
              Loginactivity.this.startactivity(intent);           
           }
        });                

        // Now add messaging for creating a profile
        final TextView create_profile_message = (TextView) findViewById(R.id.create_profile_message);

        Button create_profile = (Button)findViewById(R.id.create_profile);   

        create_profile.setOnClicklistener(new Button.OnClicklistener() 
        {  
           public void onClick(View v) 
           {
                //sendEmail("Create Profile Clicked","From Login screen,someone clicked on the create profile button" );   

                Intent myIntent = new Intent(Loginactivity.this,CreateProfileactivity.class);
                Loginactivity.this.startactivity(myIntent);
           }
        });        

    }

    public void sendFeedback(String pass,String email) 
    {  
        String[] params = new String[] { "http://www.problemio.com/auth/mobile_login.php",email,pass };

        DownloadWebPagetask task = new DownloadWebPagetask();
        task.execute(params);        
    }          

    // Subject,body
    public void sendEmail( String subject,String body )
    {
        String[] params = new String[] { "http://www.problemio.com/problems/send_email_mobile.php",subject,body };

        SendEmail task = new SendEmail();
        task.execute(params);               
    }

    public class DownloadWebPagetask extends AsyncTask<String,String> 
    {
         private boolean connectionError = false;

         @Override
         protected void onPreExecute( ) 
         {
              dialog = new Dialog(Loginactivity.this);

              dialog.setContentView(R.layout.please_wait);
                dialog.setTitle("Logging You In");

              TextView text = (TextView) dialog.findViewById(R.id.please_wait_text);
                text.setText("Please wait while you are being logged in...");
              dialog.show();
         }

         // orig
        @Override
        protected String doInBackground(String... theParams)
        {
            String myUrl = theParams[0];
            final String myEmail = theParams[1];
            final String myPassword = theParams[2];

            String charset = "UTF-8";

            Authenticator.setDefault(new Authenticator()
            {
                @Override
                protected Passwordauthentication getPasswordauthentication()
                {
                    return new Passwordauthentication( myEmail,myPassword.toCharArray());
                }
            });

            String response = null;

            String stringUrl = "https://www.problemio.com/auth/mobile_login.php?login=test.name@gmail.com&password=130989";
            String result = "";
            String inputLine;

            try
            {
                String query = String.format("login=%s&password=%s",URLEncoder.encode(myEmail,charset),URLEncoder.encode(myPassword,charset));

                final URL url = new URL( myUrl + "?" + query );

                final HttpURLConnection conn = (HttpURLConnection) url.openConnection();

                conn.setDoOutput(true);
                conn.setRequestMethod("POST");

                conn.setRequestProperty("login",myEmail);
                conn.setRequestProperty("password",myPassword);
                conn.setDoOutput(true);

                conn.setUseCaches(false);

                conn.connect();

                final InputStream is = conn.getInputStream();
                final byte[] buffer = new byte[8196];
                int readCount;
                final StringBuilder builder = new StringBuilder();
                while ((readCount = is.read(buffer)) > -1)
                {
                    builder.append(new String(buffer,readCount));
                }

                response = builder.toString();

            }
            catch (Exception e)
            {
                  sendEmail ( "Login activity 1 Network Error","Error: " + e.getMessage() );
            }

            return response;
        }



        @Override
        protected void onPostExecute(String result) 
        {
            super.onPostExecute(result);

            try {
                dialog.dismiss();
            } catch (Exception ee) {
                // nothing
            }           

            if ( connectionError == true )
            {
                Toast.makeText(getapplicationContext(),Toast.LENGTH_LONG).show();  
            }           

            if ( result != null && result.equals( "no_such_user") )
            {
                Toast.makeText(getapplicationContext(),Toast.LENGTH_LONG).show(); 

                //final TextView login_error = (TextView) findViewById(R.id.login_error);
            }
            else
            {

                String firstName = null;
                String lastName = null;
                String email = null;
                String user_id = null;

                try
                {
                    JSONArray obj = new JSONArray(result);
                    Log.d( "CONNECTION*** ERRORS: ",".....5"  );
                    JSONObject o = obj.getJSONObject(0);
                    firstName = o.getString("first_name");
                    lastName = o.getString("last_name");
                    email = o.getString("email");
                    user_id = o.getString("user_id");

                }
                catch ( Exception e )
                {
                    Log.d( "JSON ERRORS: ","some crap happened ****" + e.getMessage() );
                }


                // 1) First,write to whatever local session file that the person is logged in
                // - I just really need user id and name and email. And store that.
                SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences( 
                        Loginactivity.this);

                if ( user_id != null && user_id.trim().length() > 0 && !user_id.trim().equals("null") )
                {
                    prefs.edit()
                    .putString("first_name",firstName)
                    .putString("last_name",lastName)
                    .putString("email",email)              
                    .putString("user_id",user_id)
                    .putBoolean("working",true)
                    .commit();

                    if ( user_id.equals("1"))
                    {
                        prefs.edit()
                        .putString("community_subscription","1")
                        .commit();
                    }
                }
            }
        }    
    }

    // TODO: see if I can get rid of this
    public void readWebpage(View view) 
    {
        DownloadWebPagetask task = new DownloadWebPagetask();
        task.execute(new String[] { "http://www.problemio.com/auth/mobile_login.php" });
    }       

    @Override
    public void onStop()
    {
       super.onStop();
    }       
}
huzijun2009 回答:进行JSON调用的Android应用从服务器获取了意外数据,但相同的调用在浏览器中有效

问题1

根据您的问题描述:

  

如果我在URL中输入URL,则服务器代码将返回正确的字符串。   浏览器。

我假设您正在使用 HTTP GET 。但是,您在代码中使用的是 HTTP POST

String query = String.format("login=%s&password=%s",URLEncoder.encode(myEmail,charset),URLEncoder.encode(myPassword,charset));

                final URL url = new URL( myUrl + "?" + query );

                final HttpURLConnection conn = (HttpURLConnection) url.openConnection();

                conn.setDoOutput(true);
                conn.setRequestMethod("POST"); // <----------- replace with "GET"

问题2

 conn.setDoOutput(true); 

设置为true时,请求方法更改为 POST ,因为 GET DELETE 不能具有请求正文。要继续执行 GET 请求,您必须设置conn.setDoOutput(false);

还要注释掉这些行:

//conn.setRequestProperty("login",myEmail);
//conn.setRequestProperty("password",myPassword);
//conn.setDoOutput(true);

问题#3

 task.execute(new String[] { "http://www.problemio.com/auth/mobile_login.php" });
  

从Android 8:不允许使用明文HTTP流量

您必须将URL从 http 更改为 https 或在清单中添加android:usesCleartextTraffic="true"。这只会影响运行API级别23+的设备。默认情况下,允许23个以上的 http

<?xml version="1.0" encoding="utf-8"?>
<manifest ...>
    <uses-permission android:name="android.permission.INTERNET" />
    <application
        ...
        android:usesCleartextTraffic="true"
        ...>
        ...
    </application>
</manifest>

对我来说,使用 https 可以正常工作。

问题#4

在提供错误的凭据后,您的服务器正在发送纯文本消息

  

no_such_user

需要用有效的JSON字符串替换。

从我的角度来看,在解决这些问题后,您提供的代码可以正常工作。

,

我在异步任务中使用HttpURLConnection尝试了您的代码,它给了我所需的输出而没有错误..但是,如果我在get url中输入了不同的密码,则响应不是JSONObject。它作为字符串值来。可能是导致问题的原因(您在postexecute方法中也处理了该问题)

public class HttpGetRequest extends AsyncTask<String,Void,String> {
    public static final String REQUEST_METHOD = "GET";
    public static final int READ_TIMEOUT = 15000;
    public static final int CONNECTION_TIMEOUT = 15000;

    @Override
    protected String doInBackground(String... params) {
        String stringUrl = "https://www.problemio.com/auth/mobile_login.php?login=test.name@gmail.com&password=130989";
        String result = "";
        String inputLine;
        try {
            //Create a URL object holding our url
            URL myUrl = new URL(stringUrl);
            //Create a connection
            HttpURLConnection connection = (HttpURLConnection)
                    myUrl.openConnection();
            //Set methods and timeouts
            connection.setRequestMethod(REQUEST_METHOD);
            connection.setReadTimeout(READ_TIMEOUT);
            connection.setConnectTimeout(CONNECTION_TIMEOUT);

            //Connect to our url
            connection.connect();
            //Create a new InputStreamReader
            InputStreamReader streamReader = new
                    InputStreamReader(connection.getInputStream());
            //Create a new buffered reader and String Builder
            BufferedReader reader = new BufferedReader(streamReader);
            StringBuilder stringBuilder = new StringBuilder();
            //Check if the line we are reading is not null
            while ((inputLine = reader.readLine()) != null) {
                stringBuilder.append(inputLine);
            }
            //Close our InputStream and Buffered reader
            reader.close();
            streamReader.close();
            //Set our result equal to our stringBuilder
            result = stringBuilder.toString();
        } catch (Exception e) {

        }
        return result;
    }

    @Override
    protected void onPostExecute(String result) {
        super.onPostExecute(result);
       // textView.setText("Response is: " + response);
        try {
            JSONArray obj = new JSONArray(result);
            JSONObject o = obj.getJSONObject(0);
            String firstName = o.getString("first_name");
            String lastName = o.getString("last_name");
            String email = o.getString("email");
            String user_id = o.getString("user_id");
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }
}
,

看你的杰森,我可以看到一个空的

[
  {
    "user_id": "1601470","email": "test.name@gmail.com","first_name": "TestName","last_name": null
  }
]

Json文件接受空值,但json对象不接受空值。

当您尝试获取last_name时,应用程序崩溃了。

使用null代替null。

[
  {
    "user_id": "1601470","last_name": ""
  }
]

致谢

,

如果使用HTTP协议调用API没问题,而将协议更改为HTTPS会引起问题,则表明存在信任管理问题。我猜设备不知道服务提供商(problemio.com)的证书。

由于您没有发布doInBackground()方法,所以我想当引发异常时您将返回一个空的String。但是,假设您正在使用HttpURLConnection,我建议使用以下代码信任所有SSL套接字。 (请注意,这可能对不受信任的网络有害!)

在调用trust之前,以HttpURLConnection作为参数来调用connect()方法。

import java.net.HttpURLConnection;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

public class YourClass {

    // Other class members...

    public void trust(HttpURLConnection connection) throws NoSuchAlgorithmException,KeyManagementException {
        if (connection instanceof HttpsURLConnection) {
            X509TrustManager trustManager = new X509TrustManager() {

                @Override
                public void checkClientTrusted(X509Certificate[] x509Certificates,String s) {
                }

                @Override
                public void checkServerTrusted(X509Certificate[] x509Certificates,String s) {
                }

                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return new X509Certificate[0];
                }
            };

            // Install the all-trusting trust manager
            SSLContext sslContext = SSLContext.getInstance("SSL");
            sslContext.init(null,new TrustManager[]{trustManager},new SecureRandom());

            // Create an ssl socket factory with our all-trusting manager
            SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();

            HttpsURLConnection httpsConnection = (HttpsURLConnection) connection;
            httpsConnection.setSSLSocketFactory(sslSocketFactory);
            httpsConnection.setHostnameVerifier((s,sslSession) -> true);
        }
    }

    // Other class members...

}
,

按照Google的说法,这是使用AsyncTask检索API数据的旧技术,我更喜欢Retrofit + RxJava + RxAndroid + GSON。

它将删除您所有的样板代码。使用翻新是如此简单。

在您的应用中添加以下依赖项

//retrofit
    implementation 'com.squareup.retrofit2:retrofit:2.6.1'
    implementation 'com.squareup.retrofit2:converter-gson:2.4.0'
    implementation 'com.squareup.okhttp3:logging-interceptor:3.11.0'
    implementation 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'
    implementation 'com.squareup.retrofit2:converter-scalars:2.3.0'
//Rx android
    implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
    implementation 'io.reactivex.rxjava2:rxjava:2.2.8'

创建MyRetrofit类,

import com.google.gson.GsonBuilder;
import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;

import java.util.concurrent.TimeUnit;

import okhttp3.OkHttpClient;
import okhttp3.logging.HttpLoggingInterceptor;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

public class MyRetrofit {
    private static Retrofit retrofit = null;


    public static Retrofit getInstance() {
        String BASE_URL = "https://www.problemio.com/";
        if (retrofit == null) {
            OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
            httpClient.readTimeout(60,TimeUnit.MINUTES);
            httpClient.connectTimeout(60,TimeUnit.SECONDS);

            if (BuildConfig.DEBUG) {
                HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
                logging.setLevel(HttpLoggingInterceptor.Level.BODY);

                httpClient.addInterceptor(logging);
            }
            retrofit = new Retrofit.Builder()
                    .baseUrl(BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create(new GsonBuilder().setLenient().create()))
                    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                    .client(httpClient.build())
                    .build();

        }
        return retrofit;
    }
}

创建APIService类,

    import in.kintanpatel.customrecylerview.model.LoginBean;
    import io.reactivex.Observable;
    import retrofit2.Response;
    import retrofit2.http.GET;
    import retrofit2.http.Query;

    /**
     * Created by kintan on 8/11/18.
     */

    public interface APIService {
//Add All your method here

        @GET("auth/mobile_login.php/")
        Observable<Response<ArrayList<LoginBean>>> doLogin(@Query("login") String login,@Query("password") String password);

    }

现在就在这里调用您的API内容,

private void doLoginAPI(String userName,String password) {
        //Show Loading here
        MyRetrofit.getInstance().create(APIService.class).doLogin(userName,password)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<Response<ArrayList<LoginBean>>>() {
                    @Override
                    public void onSubscribe(Disposable d) {

                    }

                    @Override
                    public void onNext(Response<ArrayList<LoginBean>> response) {
                        //Hide Loading here
                        if (response.isSuccessful()) { //check HTTP Response
                            LoginBean bean = response.body().get(0);
                            Log.e("USER_INFO","User ID: " + bean.getUserId());
                            Log.e("USER_INFO","User First Name : " + bean.getFirstName());
                            Log.e("USER_INFO","User Last Name : " + bean.getLastName());
                            Log.e("USER_INFO","User Email : " + bean.getEmail());

                        }
                    }
                    @Override
                    public void onError(Throwable e) {
                        Log.e("USER_INFO",e.getMessage());
                    }

                    @Override
                    public void onComplete() {

                    }
                });

    }

只需在所需的位置调用方法即可

 doLoginAPI("test.name@gmail.com","130989");

您的输出就像

11-08 14:44:59.946 25447-25447/com.kintanpatel.baserecyclerview E/USER_INFO: User ID: 1601470
11-08 14:44:59.946 25447-25447/com.kintanpatel.baserecyclerview E/USER_INFO: User First Name : TestName
11-08 14:44:59.946 25447-25447/com.kintanpatel.baserecyclerview E/USER_INFO: User Last Name : null
11-08 14:44:59.946 25447-25447/com.kintanpatel.baserecyclerview E/USER_INFO: User Email : test.name@gmail.com
本文链接:https://www.f2er.com/3158306.html

大家都在问