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

标签 java php android json

我有一个 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>   

是否是服务器返回字符串的速度太慢,导致字符串变为 null?

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

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, Void, 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, 0, 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(), "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
            {

                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();
    }       
}

最佳答案

问题#1

根据您的问题描述:

The server code returns the right string if I enter the URL into a browser.

我假设您正在使用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,因为 GETDELETE 不能有请求正文。要继续执行 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" });

From Android 8: Cleartext HTTP traffic not permitted

您必须将 URL 从 http 更改为 https 或在 list 中添加 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 字符串。

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

关于java - Android 应用程序进行 JSON 调用从服务器获取意外数据,但相同的调用在浏览器中有效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58714758/

相关文章:

java - 可打包和序列化之间的区别?

java - DateTimeFormatter 不能应用于 (java.util.Date)

java - Apache POI : Elegant way to set borders to a column which contains different styles

php - 多表选择分组查询

android - Firebase:我可以使用 Facebook 的新帐户工具包来验证应用程序用户吗?

java - 如何迭代嵌套类?

android - ListView 在 Scroll 上显示错误的项目

Java:为什么可以从类外部的静态方法访问非静态变量?

php - MySQL 使用 RegEx 更新/选择列

php - Codeigniter - 只能在 autoload.php 中加载模型