Как выполнить код axios с использованием события beforeunload окна в React

#php #mysql #reactjs #axios

#php #mysql #reactjs #axios

Вопрос:

Я использую React и PHP, и мне это нужно для выполнения чего-то конкретного. Я использую Axios для отправки запросов на мои PHP-страницы, которые затем изменяют мою базу данных. Мне нужно внести обновление в таблицу моей базы данных MySQL, которая изменяет значение is_logged с true на false, если пользователь закрывает страницу или браузер. Код для этого задается в событии beforeunload окна. Однако база данных никогда не обновляется. Возможно ли вообще то, что я пытаюсь сделать в React?

Вот мой код компонента React:

 import React, { useState, useEffect } from 'react';
import axios from 'axios';
import Viewers from './Viewers';

const Live = ({ match }) => {

  window.addEventListener("beforeunload", () => {
    axios.get('http://localhost/live-streaming-app/get_viewers.php?='   token)
      .then(response => console.log(response))
  })

  // Set token from url
  const token = match.params.token

  //Get the fullname and update logged_in to true
  const [fullname, setFullname] = useState("")

  useEffect(() => {
    axios.get('http://localhost/live-streaming-app/get_user.php?token='   token)
      .then(response => {
        setFullname(response.data.fullname)
        console.log("Data", response.data)
      })
      .catch(error => console.log(error))

    return () => {
      axios.get('http://localhost/live-streaming-app/get_viewers.php?='   token)
        .then(response => console.log(response))
        .catch(error => console.log(error))
    }
  }, [token])

  //Jsx for when user is unauthorised
  const rejected = (
    <div className="container text-center pt-5">
      <h1>Rejected Connection</h1>
      <p>You are unauthorised to view this page</p>
    </div>
  )

  let my_render = ""

  if (fullname amp;amp; fullname != null) {
    my_render = <Viewers fullname={fullname} />
  } else {
    my_render = rejected
  }

  return my_render
};

export default Live;
  

Вот страница PHP, которая называется:

 <?php
require 'connect.php';

$token = $_GET['token'];

$sql = "UPDATE `viewers` SET `logged_in`='false' WHERE `live_token`='{$token}'";
if(mysqli_query($con, $sql)){
  http_response_code(201);
}
else {
  http_response_code(422);
}

exit;
  

Ответ №1:

Проблемы, с которыми нужно разобраться:

Отправляется ли запрос вообще?

Попробуйте запустить

 axios.get('http://localhost/live-streaming-app/get_viewers.php?=')
  .then(response => console.log(response))
  

в консоли вашего браузера и посмотрите, зарегистрировано ли что-либо в консоли. Проверьте вкладку Network также в ваших инструментах разработки, чтобы увидеть, был ли отправлен запрос. Если запрос вообще отправлен, то отправка запроса работает. Если нет, то у вас есть некоторые проблемы с URL, которые вам нужно будет исправить.

Токен

Отправка этого запроса

 axios.get('http://localhost/live-streaming-app/get_viewers.php?='   token)
  .then(response => console.log(response))
  

Говорит, что пустая строка будет иметь значение token . С другой стороны, ваш PHP-код предполагает, что есть параметр, вызываемый token :

 <?php
require 'connect.php';

$token = $_GET['token']; //This is the line which assumes that a parameter called token exists

$sql = "UPDATE `viewers` SET `logged_in`='false' WHERE `live_token`='{$token}'";
if(mysqli_query($con, $sql)){
  http_response_code(201);
}
else {
  http_response_code(422);
}

exit;
  

Чтобы соответствовать предположению вашего PHP-кода, вам нужно будет указать, что token является значением параметра, вызываемого token :

   window.addEventListener("beforeunload", () => {
    axios.get('http://localhost/live-streaming-app/get_viewers.php?token='   token)
      .then(response => console.log(response))
  })
  

Приведенное выше исправление должно решить проблему, о которой вы спрашиваете, но давайте не будем останавливаться на этом.

SQL-инъекция

Что, если я отправлю этот запрос (не запускайте его, если вы не создадите резервную копию) из консоли моего браузера (или cURL):

 axios.get("http://localhost/live-streaming-app/get_viewers.php?token=';delete from viewers where ''='")
  .then(response => console.log(response))
  

?

Затем ваш PHP-код выполнит это:

 UPDATE `viewers` SET `logged_in`='false' WHERE `live_token`='';delete from viewers where ''=''
  

удаление всего viewers из вашей базы данных. Используйте PDO для параметризации ваших запросов и защиты ваших запросов от подобных атак.

Краткие сведения

React — это фреймворк Javascript, что означает, что любой Javascript, на который способна ваша клиентская часть, также способен. Это правда, что некоторые функции не обязательно доступны в React way, но это не должно вас беспокоить о том, что они возможны, предполагая, что Javascript способен на это. Я склонен думать, что клиентские фреймворки станут менее полезными, когда многие вещи происходят на стороне клиента, и я думаю, что основная причина популярности клиентских фреймворков заключается в том, что большинство программистов не осознают, на сколько всего способен Javascript. Я не говорю, что клиентские фреймворки никогда не следует использовать. Я только говорю, что я видел программистов, которые были слепыми поклонниками клиентских фреймворков и технологий, что в конечном итоге привело к уничтожению проекта, над которым они работали. Итак, когда вы выбираете свой технический стек на стороне клиента, стоит проверить, какие возможности требуются вашей стороне клиента, время, необходимое для его реализации без клиентских фреймворков, и время, необходимое для его реализации с использованием каждого фреймворка, который вы могли бы рассмотреть. использование. Сравните два и подумайте о сроках и финансовых возможностях. Если вы не можете найти очевидную, очень вескую причину для использования клиентской платформы, то я не советую ее использовать. Потому что, в конце концов, если во время разработки выяснится, что по какой-то причине вам нужно использовать фреймворк на стороне клиента, вы можете легко перейти к нему с позиции отказа от использования фреймворка. Однако, если вы используете фреймворк на стороне клиента, и это оказывается невыполнимым для вашего проекта, то рефакторинг всего проекта, чтобы не использовать этот фреймворк, часто означает переопределение большей части вашей клиентской части. И такого рода проблемы чаще всего не проявляются в срочных случаях.

Ответ №2:

Нет гарантии, что асинхронные действия, выполняемые в beforeunload событии, завершатся, и axios использует асинхронный способ выполнения запросов.

Вероятно, вы можете использовать старый добрый XHR для выполнения синхронного запроса. Если вы перейдете к разделу с надписью Adapting Sync XHR use cases to the Beacon API , они рассмотрят стратегии поддержания активности запросов во время выгрузки, потому что синхронный XHR устарел.

Обратите внимание, что синхронные HTTP-запросы, как правило, плохая идея, потому что они сделают страницу невосприимчивой во время их завершения. Я не уверен, каким будет поведение синхронного запроса во время выгрузки.

Пример синхронного запроса

 logUser () {
    var params = JSON.stringify({ locked_by: '' });
    let xhr = new XMLHttpRequest()
    xhr.open('PUT',Url, false) // `false` makes the request synchronous
    xhr.setRequestHeader("Authorization", 'Bearer '   localStorage.getItem('app_access_token'))
    xhr.setRequestHeader("Content-length", params.length);
    xhr.setRequestHeader("Content-type", "application/json; charset=utf-8")
    xhr.responseType = 'arraybuffer'
    xhr.onreadystatechange = function() {//Call a function when the state changes.
    if(xhr.readyState == 4 amp;amp; xhr.status == 200) {
        alert(xhr.responseText);
    }
}

  

Примечание

Нет надежного способа выполнить что-либо при закрытии вкладки / окна. Это противоречит самому принципу «закрытия» вкладки, т. Е. освобождению ресурсов.

Я бы справился с вашей ситуацией так, чтобы интерфейс содержал что-то, что умирает само по себе, когда вкладка закрывается.

Либо откройте websocket, который вы можете использовать для многих других целей, и когда он умирает и не возвращается в течение нескольких секунд, вы знаете, что клиент отключен, либо отправьте обычный ping, пока вкладка открыта, и когда он пропустил несколько пингов, вы можете с уверенностью предположить, что клиент отключен.