Я пытаюсь заставить мое приложение для Android иметь возможность записи в базу данных MySQL, которая работает на локальном хосте на моем компьютере, но я все еще получаю ошибку тайм-аута залпа.
Почти все решения этой проблемы при переполнении стека говорят об использовании stringRequest.setRetryPolicy. Я попробовал это, как вы можете видеть далее в коде, но, к сожалению, это не решило проблему. Мой телефон - Xiaomi Mi A1 под управлением Android версии 9. Я использую WAMP v3.1.7 с PHP 7.2, MySQL 5.7 и Apache 2.4.
//URL for adding user
public static final String URL_REGISTER = "http://192.168.0.18:3000/pom/add_user.php";
//URL for reading users table
public static final String URL_DB = "http://192.168.0.18/pom/get_all_users.php";
URL_REGISTER - это URL, который я пытаюсь использовать для этого запроса. Функция ниже - та, которая делает запрос. Это в отдельном классе.
private void registerUser(final String fname, final String sname, final String phoneno, final String email, final String password){
//tag used to cancel request
String tag_string_req = "req_register";
StringRequest strReq = new StringRequest(Request.Method.POST, AppConfig.URL_REGISTER,
new Response.Listener<String>(){
@Override
public void onResponse(String response) {
try{
JSONObject jObj = new JSONObject(response);
boolean error = jObj.getBoolean("Error");
if(error){
String errorMsg = jObj.getString("error_msg");
Toast.makeText(getApplicationContext(), "Error occurred: " + errorMsg,
Toast.LENGTH_LONG).show();
}
//Navigate to page that displays DB entries
Intent intent = new Intent(Registration.this, DBView.class);
startActivity(intent);
}catch(JSONException e) {
e.printStackTrace();
}
}
},
new Response.ErrorListener(){
@Override
public void onErrorResponse(VolleyError error) {
if(error instanceof AuthFailureError){
Log.e(TAG, "Authorisation Failure Error: " + error.getMessage());
Toast.makeText(getApplicationContext(), "Registration Error: Authorisation Failure Error", Toast.LENGTH_LONG).show();
}else if(error instanceof NetworkError){
Log.e(TAG, "NetworkError: " + error.getMessage());
Toast.makeText(getApplicationContext(), "Registration Error: Network Error", Toast.LENGTH_LONG).show();
}else if(error instanceof ParseError){
Log.e(TAG, "Parse Error: " + error.getMessage());
Toast.makeText(getApplicationContext(), "Registration Error: Parse Error", Toast.LENGTH_LONG).show();
}else if(error instanceof ServerError){
Log.e(TAG, "Server Error: " + error.getMessage());
Toast.makeText(getApplicationContext(), "Registration Error: Server Error", Toast.LENGTH_LONG).show();
}else if(error instanceof TimeoutError){
Log.e(TAG, "Timeout Error: " + error.getMessage());
Toast.makeText(getApplicationContext(), "Registration Error: Timeout Error", Toast.LENGTH_LONG).show();
}else if(error instanceof NoConnectionError){
Log.e(TAG, " No Connection Error: " + error.getMessage());
Toast.makeText(getApplicationContext(), "Registration Error: No Connection Error", Toast.LENGTH_LONG).show();
}
}
}){
@Override
protected Map<String, String> getParams(){
//posting params to register url
Map<String, String> params = new HashMap<String, String>();
params.put("First_name", fname);
params.put("Surname", sname);
params.put("PhoneNo", phoneno);
params.put("Email", email);
params.put("Password", password);
return params;
}
};
strReq.setRetryPolicy(new DefaultRetryPolicy(50000,DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
//Add to requestQueue
Log.d(TAG, strReq.toString());
AppController.getInstance().addToRequestQueue(strReq, tag_string_req);
}
addToRequestQueue:
public RequestQueue getRequestQueue(){
if(mRequestQueue == null){
mRequestQueue = Volley.newRequestQueue(getApplicationContext());
}
return mRequestQueue;
}
public <T> void addToRequestQueue(Request<T> req, String tag){
req.setTag(TextUtils.isEmpty(tag) ? TAG : tag);
getRequestQueue().add(req);
}
add_user:
<?php
/ *
* Следующий код создаст новую строку продукта
* Все детали продукта считываются из HTTP Post Request
* /
//create array for json response
$response = array();
//check for required fields
//&& isset($_POST['sname'] && isset($_POST['phoneno']) && isset($_POST['email']) && isset($_POST['password'])
if(isset($_POST['fname'])){
$fname = $_POST['fname'];
$sname = $_POST['sname'];
$phoneno = $_POST['phoneno'];
$email = $_POST['email'];
$password = $_POST['password'];
//include db connect
require_once __DIR__ . "/db_connect.php";
//connect to db
$db = new DB_CONNECT();
//mysql inserting a new row
$result = mysqli_query("INSERT INTO users(First_name, Surname, PhoneNo, Email, Password) VALUES('$fname', '$sname', '$phoneno','$email', '$password')");
//check if row is inserted
if($result){
$response['success'] = 1;
$response['message'] = "Successfully inserted";
//echoing JSON response
echo json_encode($response);
}else{
//failed to insert row
$response['success'] = 0;
$response['message'] = "An error occured.";
//echo JSON response
echo json_encode($response);
}
}else{
$response['success'] = 0;
$response['message'] = "required field(s) missing.";
//echo JSON response
echo json_encode($response);
}?>
db_connect
class DB_CONNECT {
//constructor
function __construct(){
//connecting to database
$this -> connect();
}
//destructor
function __destruct(){
//closing db connection
$this -> close();
}
/*
* Function to connect to database
*/
function connect(){
//import database connection variables
require_once __DIR__ . '/db_config.php';
//connecting to mysql database
$con = mysqli_connect(DB_SERVER, DB_USER, DB_PASSWORD) or die(mysqli_connect_error()) or die(mysqli_error());
//selecting database
$db = mysqli_select_db(DB_DATABASE) or die(mysqli_error());
//returning connection cursor
return $con;
}
function close(){
//closing db connection
mysqli_close();
}
}?>
DB_CONFIG
define('DB_USER', "root"); //db user
define('DB_PASSWORD', ""); //db password
define('DB_DATABASE', "pom"); //database name
define('DB_SERVER', "localhost");
?>
Выше приведен весь код, который должен вызываться при попытке подключиться к БД. Он должен добавить новую запись в таблицу users в моей базе данных MySQL, а в приложении он должен перевести меня на другой экран, но в таблице нет записей, и приложение вместо этого выдает ошибку тайм-аута. Локальный IP-адрес моего компьютера - 192.168.0.18, а для моего телефона - 192.168.0.55. Я пробовал порт 80, порт не указан, и сейчас я пытаюсь 3000, но все они дают ошибку времени ожидания. Последнее, что может быть полезно, - это то, что запрос даже не отображается в журнале apache. Я ожидаю увидеть что-то вроде этого
192.168.0.55 - - [27/Jun/2019:11:30:01 +0100] "POST /pom/add_user.php HTTP/1.1" 200 52
но в самый последний раз, когда я его запускал, в журнале доступа или журнале ошибок нет записей.
Обновление:
Я решил проверить Wireshark, чтобы проверить, проходят ли пакеты. Я получил этот захват:
211 18.541329 192.168.0.55 192.168.0.18 TCP 74 38066 → 80 [SYN] Seq=0 Win=65535 Len=0 MSS=1460 SACK_PERM=1 TSval=15216282 TSecr=0 WS=256
214 19.556572 192.168.0.55 192.168.0.18 TCP 74 [TCP Retransmission] 38066 → 80 [SYN] Seq=0 Win=65535 Len=0 MSS=1460 SACK_PERM=1 TSval=15216383 TSecr=0 WS=256234
234 21.556683 192.168.0.55 192.168.0.18 TCP 74 [TCP Retransmission] 38066 → 80 [SYN] Seq=0 Win=65535 Len=0 MSS=1460 SACK_PERM=1 TSval=15216583 TSecr=0 WS=256
287 25.554442 192.168.0.55 192.168.0.18 TCP 74 [TCP Retransmission] 38066 → 80 [SYN] Seq=0 Win=65535 Len=0 MSS=1460 SACK_PERM=1 TSval=15216984 TSecr=0 WS=256
396 33.572515 192.168.0.55 192.168.0.18 TCP 74 [TCP Retransmission] 38066 → 80 [SYN] Seq=0 Win=65535 Len=0 MSS=1460 SACK_PERM=1 TSval=15217786 TSecr=0 WS=256
Кажется, что это не удается рукопожатие. Значит ли это, что у меня не правильно настроен мой apache? Или это проблема брандмауэра. Я добавил исключения, чтобы разрешить трафик с 192.168.0.55 до 192.168.0.18 на моем компьютере и межсетевом экране маршрутизатора.
Обновление 2:
Теперь это работает. Рукопожатие там, а также HTTP-запрос и 200 ОК. Для тех, кто страдает той же проблемой, это проблема с брандмауэром. Для меня есть 3 брандмауэра:
- Защитник Windows
- Commodo антивирус
- Брандмауэр маршрутизатора
Я установил правила для всех из них, чтобы пропускать трафик. К сожалению, окна были окнами, но по какой-то причине они все еще блокировали. Когда я отключил Windows Defender все вместе, пакеты прошли. Несмотря на то, что у меня есть входящее правило для защитника, оно все равно не понравилось, так что это может быть что-то, о чем стоит помнить.