[Formulario web] Manejo de datos de usuario-2 (notas mdn)

75be4c7f0a61b86daf6cbe11f46db79e.png

8. Pseudoclases de UI

8.1 ¿Qué tipo de pseudoclases existen?

Las pseudoclases primitivas relacionadas con formularios que podemos usar (a partir de CSS 2.1) son:

  • :hover : Selecciona un elemento solo cuando el puntero del mouse está sobre él.

  • :focus : seleccione solo el elemento cuando esté enfocado (es decir, seleccionado con la tecla tab en el teclado).

  • :activo : Selecciona el elemento solo cuando está activo (es decir, seleccionado haciendo clic o la tecla Retorno/Entrar en el teclado).

CSS Selector Level 3 y CSS Basic UI Level 3  agregaron más pseudoclases relacionadas con formularios HTML . Brevemente, las cosas principales que veremos son:

  • :requerido y :opcional : para controles de formulario requeridos u opcionales.

  • :válido y :inválido, :en rango y :fuera de rango : para controles de formulario, es válido/inválido según las restricciones de validación de formulario establecidas en él , o dentro/fuera de rango .

  • :enabled y :disabled, :read-only y :read-write : para controles de formulario que están habilitados o deshabilitados (por ejemplo, el atributo HTML deshabilitado está configurado) y para controles de formulario de lectura-escritura o de solo lectura (por ejemplo , se establece el atributo HTML de sólo lectura).

  • :checked, :indeterminate y :default : para casillas de verificación marcadas y botones de opción, respectivamente, en un estado indeterminado (ni marcado ni marcado), y opciones seleccionadas de forma predeterminada al cargar la página (por ejemplo, una <input type="checkbox" > con el conjunto de atributos marcado, o un elemento <option> con el conjunto de atributos seleccionado).

Nota: Muchas de las pseudoclases analizadas aquí se ocupan de establecer y controlar restricciones de validación basadas en el estado de validación de los controles de formulario (¿son válidos sus datos?). Aprenderá más sobre cómo configurar y controlar restricciones de validación en nuestro próximo artículo Cliente- Conocimiento secundario sobre validación de formularios, pero por ahora mantendremos las cosas simples sobre la validación de formularios para que no haya confusión.

8.2 Aplicar estilos a los controles de entrada según sea necesario o no

Si la entrada del formulario es obligatoria (debe completarse antes de enviar el formulario) u opcional .
Los elementos <input>, <select> y <textarea> tienen un atributo obligatorio disponible que, cuando se establece, significa que debe completar el control antes de que el formulario pueda enviarse correctamente . Por ejemplo:

2e5e578a7ed57048d6b4d1d69a1f0327.png

<form>
  <fieldset> <!-- 定义字段集 -->
    <legend>Feedback form</legend> <!-- 定义字段集标题 -->
    <div>
      <label for="fname">First name: </label> <!-- 定义标签 -->
      <input id="fname" name="fname" type="text" required /> <!-- 定义文本输入框,要求必填 -->
    </div>
    <div>
      <label for="lname">Last name: </label> <!-- 定义标签 -->
      <input id="lname" name="lname" type="text" required /> <!-- 定义文本输入框,要求必填 -->
    </div>
    <div>
      <label for="email">
        Email address (include if you want a response):
      </label> <!-- 定义标签 -->
      <input id="email" name="email" type="email" /> <!-- 定义电子邮件输入框 -->
    </div>
    <div><button>Submit</button></div> <!-- 定义提交按钮 -->
  </fieldset>
</form>

Aquí, se requieren el nombre y el apellido, pero la dirección de correo electrónico es opcional.

Ambos estados se pueden hacer coincidir utilizando  las  pseudoclases :required y :optional . Los controles de formulario obligatorios tendrán un borde negro, los controles de formulario opcionales tendrán un borde plateado.

input:required {
  border: 1px solid black;
}

input:optional {
  border: 1px solid silver;
}

Envíe sin completar el formulario y observe los mensajes de error de validación del lado del cliente que el navegador le brinda de forma predeterminada .
La convención estándar en la web para un estado requerido es un asterisco (*), o asociar la palabra "requerido" con el control asociado.

Nota: Si un botón de opción en un grupo de botones de opción con el mismo nombre tiene el atributo requerido, todos los botones de opción no serán válidos hasta que se seleccione uno, pero solo el botón de opción al que se le asignó este atributo coincidirá realmente con:requerido.

8.3 Generar contenido usando pseudoclases

Utilice  los pseudoelementos ::before y ::afterel atributo de contenido para hacer que una parte del contenido aparezca antes o después del elemento afectado.
Esta parte del contenido no se agrega al DOM, por lo que es invisible para los lectores de pantalla; es parte de los estilos del documento . Esto es útil
cuando desea agregar un indicador visual a un elemento , como una etiqueta o un ícono, pero no desea que la tecnología de asistencia pueda detectarlo .

Por ejemplo, en nuestro  ejemplo de botón de opción personalizado , utilizamos contenido generado para manejar el posicionamiento y la animación del círculo interior cuando se selecciona el botón de opción :

79b2b7e96865bc8c609d8f89266bca43.png

<fieldset>
      <legend>Choose your favourite fruit</legend>

      <p>
        <label>
          <input type="radio" name="fruit" value="cherry">
          Cherry
        </label>
      </p>
      <p>
        <label>
          <input type="radio" name="fruit" value="banana">
          Banana
        </label>
      </p>
      <p>
        <label>
          <input type="radio" name="fruit" value="strawberry">
          Strawberry
        </label>
      </p>
    </fieldset>
input[type="radio"] {
  appearance: none; /* 移除默认外观 */
}

input[type="radio"] {
  width: 20px; /* 设置宽度为20px */
  height: 20px; /* 设置高度为20px */
  border-radius: 10px; /* 设置圆角半径为10px */
  border: 2px solid gray; /* 设置边框为2px实线灰色 */
  /* 调整单选框在文本基线上的位置 */
  vertical-align: -2px;
  outline: none; /* 移除轮廓线 */
}

input[type="radio"]::before {
  display: block; /* 设置display属性为block */
  content: " "; /* 设置内容为空格 */
  width: 10px; /* 设置宽度为10px */
  height: 10px; /* 设置高度为10px */
  border-radius: 6px; /* 设置圆角半径为6px */
  background-color: red; /* 设置背景颜色为红色 */
  font-size: 1.2em; /* 设置字体大小为1.2em */
  transform: translate(3px, 3px) scale(0); /* 设置变换效果,平移3px并缩放为0 */
  transform-origin: center; /* 设置变换原点为中心 */
  transition: all 0.3s ease-in; /* 设置过渡效果,所有属性在0.3秒内以ease-in方式过渡 */
}

input[type="radio"]:checked::before {
  transform: translate(3px, 3px) scale(1); /* 当单选框被选中时,设置变换效果,平移3px并缩放为1 */
  transition: all 0.3s cubic-bezier(0.25, 0.25, 0.56, 2); /* 设置过渡效果,所有属性在0.3秒内以cubic-bezier方式过渡 */
}

Volviendo a nuestro ejemplo anterior requerido/opcional , esta vez no cambiaremos la apariencia de la entrada en sí. Usaremos el contenido generado para agregar una etiqueta indicadora.

e7673aeb49272f194a1108d7edd3563a.png

<form>
  <fieldset> <!-- 定义字段集 -->
    <legend>Feedback form</legend> <!-- 定义字段集标题 -->
    <p>Required fields are labelled with "required".</p> <!-- 添加段落说明 -->
    <div>
      <label for="fname">First name: </label> <!-- 定义标签 -->
      <input id="fname" name="fname" type="text" required> <!-- 定义文本输入框,要求必填 -->
      <span></span>
    </div>
    <div>
      <label for="lname">Last name: </label> <!-- 定义标签 -->
      <input id="lname" name="lname" type="text" required> <!-- 定义文本输入框,要求必填 -->
      <span></span>
    </div>
    <div>
      <label for="email">Email address (include if you want a response): </label> <!-- 定义标签 -->
      <input id="email" name="email" type="email"> <!-- 定义电子邮件输入框 -->
      <span></span>
    </div>
    <div><button>Submit</button></div> <!-- 定义提交按钮 -->
  </fieldset>
</form>
body {
  font-family: 'Josefin Sans', sans-serif; /* 设置字体为'Josefin Sans' */
  margin: 20px auto; /* 设置顶部和底部边距为20px,并使body水平居中 */
  max-width: 460px; /* 设置body的最大宽度为460px */
}

fieldset {
  padding: 10px 30px 0; /* 设置字段集的内边距 */
}

legend {
  color: white; /* 设置字段集标题的颜色为白色 */
  background: black; /* 设置字段集标题的背景颜色为黑色 */
  padding: 5px 10px; /* 设置字段集标题的内边距 */
}
/*由于 input 和 label 都设置了 width: 100%,span 会沉到输入框下一行中。为了修复这一点,我们令父 <div> 为弹性容器,同时令它如果内容变得太长,就把它的内容换行:这样做的效果是,标签和输入是分开的,因为它们都是 width: 100%,但 <span> 的宽度是 0,所以它可以和 input 位于同一行。*/
fieldset > div {
  margin-bottom: 20px; /* 设置字段集内直接子div元素的底部边距为20px */
  display: flex; /* 设置display属性为flex */
  flex-flow: row wrap; /* 设置flex容器为行方向并换行 */
}

button, label, input {
  display: block; /* 设置display属性为block */
  font-family: inherit; /* 继承父元素的字体 */
  font-size: 100%; /* 设置字体大小为100% */
  padding: 0; /* 设置内边距为0 */
  margin: 0; /* 设置外边距为0 */
  box-sizing: border-box; /* 设置盒模型为border-box */
  width: 100%; /* 设置宽度为100% */
  padding: 5px; /* 设置内边距为5px */
  height: 30px; /* 设置高度为30px */
}
input {
  box-shadow: inset 1px 1px 3px #ccc; /* 添加内阴影效果 */
  border-radius: 5px; /* 添加圆角效果 */
}

input:hover, input:focus {
  background-color: #eee; /* 当鼠标悬停或输入框获得焦点时,设置背景颜色为#eee */
}

input + span {
  position: relative; /* 设置相对定位 */
}

input:required + span::after {
  font-size: 0.7rem; /* 设置字体大小为0.7rem */
  position: absolute; /* 设置绝对定位 */
  content: "required"; /* 设置内容为"required" */
  color: white; /* 设置颜色为白色 */
  background-color: black; /* 设置背景颜色为黑色 */
  padding: 5px 10px; /* 设置内边距为5px和10px */
  top: -26px; /* 设置顶部边距为-26px */
  left: -70px; /* 设置左边距为-70px */
}

button {
  width: 60%; /* 设置宽度为60% */
  margin: 0 auto; /* 水平居中按钮 */
}

8.4 Agregar estilos a los controles según si los datos son válidos

Otro concepto básico realmente importante en la validación de formularios es si los datos de los controles de formulario son válidos y los controles de formulario con restricciones se pueden ubicar de acuerdo con estos estados .
:valid y :invalid
Utilice las pseudoclases :valid y :invalid para localizar controles de formulario .

  • Los controles de formulario sin validación de restricciones siempre son válidos y, por lo tanto, siempre coinciden con :válido.

  • Los controles de formulario con conjunto requerido y sin valor no son válidos; coinciden con :invalid y :required.

  • Los controles con validación incorporada , como <input type="email"> o <input type="url">, coinciden con :invalid (pero son válidos cuando están vacíos).

  • Los controles cuyo valor actual esté fuera de los límites de rango especificados por los atributos mínimo y máximo coincidirán con :invalid, pero también coincidirán con :out-of-range, como veremos más adelante.

  • Hay algunas otras formas de hacer que los elementos :valid/:invalid coincidan, que verá en el artículo sobre validación de formularios del lado del cliente.

Un ejemplo :válido/:inválido simple:

4891f6c9397bbe31d4e14fb2ec0c303e.png

input + span {
  position: relative;/* 设置相对定位 */
}

input + span::before {
  position: absolute; /* 设置绝对定位 */
  right: -20px; /* 设置右边距为-20px */
  top: 5px; /* 设置顶部边距为5px */
}

input:invalid {
  border: 2px solid red; /* 当输入无效时,设置边框为2px实线红色 */
}

input:invalid + span::before {
  content: '?'; /* 当输入无效时,在相邻的span元素的:before伪元素中添加"?" */
  color: red; /* 设置颜色为红色 */
}

input:valid + span::before {
  content: '?'; /* 当输入有效时,在相邻的span元素的:before伪元素中添加"?" */
  color: green; /* 设置颜色为绿色 */
}

Configuramos los <span> en posición: relativa para que podamos colocar el contenido generado en relación con ellos . Colocamos absolutamente diferentes contenidos generados dependiendo de si los datos del formulario son válidos o no: una casilla de verificación verde o una cruz roja respectivamente. Para agregar un poco más de urgencia a los datos no válidos, también hemos espesado los datos de entrada con un borde rojo cuando no son válidos.

Nota: Usamos ::before para agregar estas etiquetas porque ya usamos ::after para agregar la etiqueta "requerida" .


Hay dos pseudoclases relacionadas a considerar para datos dentro y fuera de rango : dentro de rango y: fuera de rango . Estos coinciden con entradas numéricas, donde los límites de rango se especifican mediante min y max , para datos cuyos datos están dentro o fuera del rango especificado, respectivamente.

Nota: Los tipos de entrada numérica incluyen fecha, mes, semana, hora, fecha y hora local, número y rango. Las entradas con datos dentro del rango también coincidirán con la pseudoclase :valid, y las entradas con datos fuera del rango también coincidirán con la pseudoclase :invalid.

Ejemplo:

La entrada numérica se ve así:

<div>
  <label for="age">Age (must be 12+): </label>
  <input id="age" name="age" type="number" min="12" max="120" required />
  <span></span>
</div>

El estilo CSS se ve así:

input + span {
  position: relative; /* 设置相对定位 */
}

input + span::after {
  font-size: 0.7rem; /* 设置字体大小为0.7rem */
  position: absolute; /* 设置绝对定位 */
  padding: 5px 10px; /* 设置内边距为5px和10px */
  top: -26px; /* 设置顶部边距为-26px */
}

input:required + span::after {
  color: white; /* 当输入要求必填时,设置颜色为白色 */
  background-color: black; /* 设置背景颜色为黑色 */
  content: "Required"; /* 设置内容为"Required" */
  left: -70px; /* 设置左边距为-70px */
}

input:out-of-range + span::after {
  color: white; /* 当输入超出范围时,设置颜色为白色 */
  background-color: red; /* 设置背景颜色为红色 */
  width: 155px; /* 设置宽度为155px */
  content: "Outside allowable value range"; /* 设置内容为"Outside allowable value range" */
  left: -182px; /* 设置左边距为-182px */
}

beae05b75e3c02d6abf144ff40ceee71.png

Es posible que una entrada numérica sea requerida y esté fuera de rango , entonces, ¿qué sucede? Debido a que la regla :fuera de rango aparece más tarde en el código fuente que la regla :required, entran en juego reglas en cascada y se muestra un mensaje "fuera de rango".

Cuando la página se carga por primera vez, dice "obligatorio", con una cruz y un borde rojos. Cuando ingresa una edad válida (es decir, en el rango de 12 a 120), la entrada se vuelve válida. Sin embargo, si cambia la entrada de edad a fuera del rango, aparecerá el mensaje "Fuera del rango de valores permitidos" en lugar de "obligatorio" .

8.5 Estilo de controles de entrada habilitados o deshabilitados, de solo lectura o de lectura y escritura

Un elemento habilitado es un elemento que se puede activar; se puede seleccionar, hacer clic, ingresar, etc. Por otro lado, con un elemento deshabilitado no se puede interactuar de ninguna manera, sus datos ni siquiera se enviarán al servidor .
Puede utilizar : enable y :disabled para localizar .
Eche un vistazo a un ejemplo de cómo hacer esto.
Su código HTML es un formulario simple con entrada de texto, además de una casilla de verificación para activar y desactivar y desactivar la dirección de facturación. El campo de dirección de facturación está deshabilitado de forma predeterminada . Se puede ver una versión en ejecución aquí.

8f6e1226e1dcf30a4dade9f285cfab10.png

<form>
  <fieldset id="shipping"> <!-- 定义字段集 -->
    <legend>Shipping address</legend> <!-- 定义字段集标题 -->
    <div>
      <label for="name1">Name: </label> <!-- 定义标签 -->
      <input id="name1" name="name1" type="text" required /> <!-- 定义文本输入框,要求必填 -->
    </div>
    <div>
      <label for="address1">Address: </label> <!-- 定义标签 -->
      <input id="address1" name="address1" type="text" required /> <!-- 定义文本输入框,要求必填 -->
    </div>
    <div>
      <label for="pcode1">Zip/postal code: </label> <!-- 定义标签 -->
      <input id="pcode1" name="pcode1" type="text" required /> <!-- 定义文本输入框,要求必填 -->
    </div>
  </fieldset>
  <fieldset id="billing"> <!-- 定义字段集 -->
    <legend>Billing address</legend> <!-- 定义字段集标题 -->
    <div>
      <label for="billing-checkbox">Same as shipping address:</label> <!-- 定义标签 -->
      <input type="checkbox" id="billing-checkbox" checked /> <!-- 定义复选框,默认选中 -->
    </div>
    <div>
      <label for="name" class="billing-label disabled-label">Name: </label> <!-- 定义标签,添加类名 -->
      <input id="name" name="name" type="text" disabled required /> <!-- 定义文本输入框,禁用并要求必填 -->
    </div>
    <div>
      <label for="address2" class="billing-label disabled-label">
        Address:
      </label> <!-- 定义标签,添加类名 -->
      <input id="address2" name="address2" type="text" disabled required /> <!-- 定义文本输入框,禁用并要求必填 -->
    </div>
    <div>
      <label for="pcode2" class="billing-label disabled-label">
        Zip/postal code:
      </label> <!-- 定义标签,添加类名  我们也想把相应的文本标签弄成灰色。这些并不那么容易选择,所以我们用一个类来为它们提供这种风格。-->
      <input id="pcode2" name="pcode2" type="text" disabled required /> <!-- 定义文本输入框,禁用并要求必填 -->
    </div>
  </fieldset>

  <div><button>Submit</button></div> <!-- 定义提交按钮 -->
</form>
input[type="text"]:disabled { /* 选择所有被禁用的文本输入框 */
  background: #eee; /* 背景颜色为浅灰色 */
  border: 1px solid #ccc; /* 边框为1像素宽,实线,颜色为深灰色 */
}

.disabled-label { /* 选择所有类名为 disabled-label 的元素 */
  color: #aaa; /* 文本颜色为深灰色 */
}

Finalmente usamos código JavaScript para alternar el estado deshabilitado del campo de dirección de facturación :

// 等待页面完成加载
document.addEventListener(
  "DOMContentLoaded",
  () => {
    // 向复选框附加 `change` 事件
    document
      .getElementById("billing-checkbox")
      .addEventListener("change", toggleBilling);
  },
  false,/*布尔值如果是true,表示在捕获阶段调用事件处理程序;如果是false,表示在冒泡阶段调用事件处理程序。*/
);

function toggleBilling() {
  // 选择账单文本字段
  const billingItems = document.querySelectorAll('#billing input[type="text"]');
  // 选择账单文本标签
  const billingLabels = document.querySelectorAll(".billing-label");

  // 切换账单文本字段和标签
  for (let i = 0; i < billingItems.length; i++) {
    billingItems[i].disabled = !billingItems[i].disabled;
    //通过修改标签的类属性 达到修改标签启用或禁用的效果
    if (
      billingLabels[i].getAttribute("class") === "billing-label disabled-label"
    ) {
      billingLabels[i].setAttribute("class", "billing-label");
    } else {
      billingLabels[i].setAttribute("class", "billing-label disabled-label");
    }
  }
}

Utiliza  el evento de cambio para permitir al usuario habilitar/deshabilitar campos de facturación y alternar el estilo de las etiquetas asociadas .

Sólo lectura o lectura-escritura
Similar a :disabled y :enabled, las pseudoclases :read-only y :read-write  cambian entre los dos estados de las entradas del formulario. Las entradas de solo lectura envían sus valores al servidor, pero el usuario no puede editarlos , mientras que las entradas de lectura y escritura significan que se pueden editar; este es su estado predeterminado.
Utilice  el atributo de solo lectura para hacer que una entrada sea de solo lectura .

Como ejemplo , imagine una página de confirmación donde el desarrollador envía los detalles completados en la página anterior, con el objetivo de permitir al usuario verificar todos los detalles en un solo lugar, agregar los datos finales requeridos y luego confirmar el pedido enviando él. En este punto, todos los datos del formulario final se pueden enviar al servidor de una sola vez. (Consulte readonly-confirmation.html para ver un ejemplo en ejecución.

4d0bfe25d5bdcd7ed58ca8a138a31077.png

Un fragmento de HTML es el siguiente, tenga en cuenta el  atributo de solo lectura :

<div>
  <label for="name">Name: </label>
  <input id="name" name="name" type="text" value="Mr Soft" readonly />
</div>

Si intenta ejecutar el ejemplo , encontrará que el grupo superior de elementos del formulario no se puede enfocar y, cuando se envíe el formulario, se enviará su valor.
Usamos las pseudoclases :read-only y :read-write para diseñar controles de formulario :

:is(
    input:read-only,
    input:-moz-read-only,
    textarea:-moz-read-only,
    textarea:read-only
  ) {
  /* 选择所有只读的输入框和文本域 */
  border: 0; /* 边框宽度为0 */
  box-shadow: none; /* 没有阴影 */
  background-color: white; /* 背景颜色为白色 */
}

:is(textarea:-moz-read-write, textarea:read-write) {
  /* 选择所有可写的文本域 */
  box-shadow: inset 1px 1px 3px #ccc; /* 内阴影为1像素宽,颜色为深灰色 */
  border-radius: 5px; /* 边框圆角半径为5像素 */
}

Nota:  :enabled y :read-write  son otras dos pseudoclases probablemente poco utilizadas que describen el estado predeterminado de un elemento de entrada .

8.6 Estados de la radio y del botón de verificación: estados seleccionado, predeterminado e intermedio

Los botones de opción y las casillas de verificación se pueden marcar o desmarcar. Pero también hay otros estados a considerar :

  • :default : Coincide con los botones de opción/casillas de verificación que están marcados de forma predeterminada al cargar la página (es decir, configurando el atributo marcado), estos coinciden con la  pseudoclase :default incluso si el usuario la desmarca.

  • :indeterminate : cuando los botones de opción/casillas de verificación no están marcados ni deseleccionados, son estados intermedioscoincidirán con la pseudoclase :indeterminate . Los detalles se exponen a continuación.

:checked
Cuando los botones de radio o las casillas de verificación están marcados, coincidirán con la pseudoclase :checked.
El uso más común es agregar diferentes estilos cuando la casilla de verificación o el botón de radio están marcados , en este caso, habiendo eliminado el estilo predeterminado del sistema. con apariencia: none; ,
el código :checked en nuestro ejemplo de botón de opción con estilo se ve así:

input[type="radio"]::before {
  /* 选择所有单选按钮的伪元素 ::before */
  display: block; /* 显示为块级元素 */
  content: " "; /* 内容为空格 */
  width: 10px; /* 宽度为10像素 */
  height: 10px; /* 高度为10像素 */
  border-radius: 6px; /* 边框圆角半径为6像素 */
  background-color: red; /* 背景颜色为红色 */
  font-size: 1.2em; /* 字体大小为1.2em */
  transform: translate(3px, 3px) scale(0); /* 平移3像素并缩放为0 */
  transform-origin: center; /* 变换原点为中心 */
  transition: all 0.3s ease-in; /* 过渡时间为0.3秒,缓动函数为ease-in */
}

input[type="radio"]:checked::before {
  /* 选择所有被选中的单选按钮的伪元素 ::before */
  transform: translate(3px, 3px) scale(1); /* 平移3像素并缩放为1 */
  transition: all 0.3s cubic-bezier(0.25, 0.25, 0.56, 2); /* 过渡时间为0.3秒,缓动函数为cubic-bezier(0.25,0.25,0.56,2) */
}

2b053d0ec30ec447caf309265997a011.png

Básicamente, usamos el pseudoelemento ::before para diseñar el "círculo interno" de los botones de opción y
usamos una  transición  para darle una animación agradable cuando se selecciona . Lo bueno de usar transformaciones en lugar de ancho/alto de transición es que puedes usar transform-origin para hacerlo crecer desde el centro del círculo en lugar de hacer que parezca crecer desde las esquinas del círculo .

:default y :indeterminate La
pseudoclase :default coincide con un botón de opción o casilla de verificación que está marcado de forma predeterminada al cargar la página , incluso si no está marcado . Los botones de opción o casillas de verificación mencionados anteriormente coinciden con la pseudoclase :indeterminada cuando no están marcados ni desmarcados. Los elementos inciertos incluyen:

  • Entrada <input/radio> , cuando todos los botones de opción en el grupo del mismo nombre están desmarcados

  • <input/checkbox> entrada cuyo atributo indeterminado se establece en verdadero mediante código JavaScript.

  • Un elemento <progreso> sin valor.

Algunas versiones modificadas de los ejemplos anteriores que recuerdan al usuario cuál es la opción predeterminada y le dan estilo al botón de opción en caso de incertidumbre .

<fieldset>
      <legend>Choose your favourite fruit</legend>

      <p>
        <input type="radio" name="fruit" value="cherry" id="cherry">
        <label for="cherry">Cherry</label>
        <span></span>
      </p>
      <p>
        <input type="radio" name="fruit" value="banana" id="banana" checked>
        <label for="banana">Banana</label>
        <span></span>
      </p>
      <p>
        <input type="radio" name="fruit" value="strawberry" id="strawberry">
        <label for="strawberry">Strawberry</label>
        <span></span>
      </p>
    </fieldset>

Para el ejemplo :default, agregamos el atributo check a la entrada del botón de opción central , por lo que se verificará de forma predeterminada al cargar . Luego le damos estilo a esto con el siguiente CSS:

input ~ span {
  /* 选择所有与 input 元素同级且在其后面的 span 元素 */
  position: relative; /* 定位方式为相对定位 */
}

input:default ~ span::after {
  /* 选择所有与默认 input 元素同级且在其后面的 span 元素的伪元素 ::after */
  font-size: 0.7rem; /* 字体大小为0.7rem */
  position: absolute; /* 定位方式为绝对定位 */
  content: "Default"; /* 内容为 "Default" */
  color: white; /* 文本颜色为白色 */
  background-color: black; /* 背景颜色为黑色 */
  padding: 5px 10px; /* 内边距为5像素上下,10像素左右 */
  right: -65px; /* 距离右边界-65像素 */
  top: -3px; /* 距离上边界-3像素 */
}

El elemento seleccionado inicialmente al cargar la página proporciona una pequeña etiqueta "predeterminada".
Aquí estamos usando el combinador de hermanos universal (~) en lugar del combinador de hermanos adyacente (+) NOTA: También puede encontrar una demostración en vivo de este ejemplo
en radios-checked-default.html en GitHub .

Para el  ejemplo: indeterminado , no tenemos un botón de opción seleccionado predeterminado. Usamos el siguiente CSS para diseñar un botón de opción indeterminado :

c182079f99dc8548f124714323b3727a.png

input[type="radio"]:indeterminate {
  /* 选择所有处于不确定状态的单选按钮 */
  border: 2px solid red; /* 边框为2像素宽,实线,颜色为红色 */
  animation: 0.4s linear infinite alternate border-pulse; /* 动画名称为border-pulse,持续时间为0.4秒,线性缓动函数,无限循环,交替播放 */
}

@keyframes border-pulse {
  /* 定义关键帧动画 border-pulse */
  from {
    /* 起始状态 */
    border: 2px solid red; /* 边框为2像素宽,实线,颜色为红色 */
  }

  to {
    /* 结束状态 */
    border: 6px solid red; /* 边框为6像素宽,实线,颜色为红色 */
  }
}

Nota: También puede encontrar un ejemplo práctico de este ejemplo en GitHub en radios-checked-indeterminate.html.

Además de los estados seleccionado
y no seleccionado, la casilla de verificación tiene un tercer estado: indeterminado . La propiedad indeterminada del objeto HTMLInputElement  establecida
por  JavaScript . En la mayoría de los navegadores, la casilla de verificación en el estado indeterminado tiene una línea horizontal dentro del cuadro . La mayoría Lo común es cuando una casilla de verificación "posee" algunas subopciones (también casillas de verificación). Si todas las subopciones están marcadas, la casilla de propiedad está marcada, y si ninguna de ellas está marcada, la casilla de propiedad está desmarcada. La casilla de verificación de propiedad está en un estado indeterminado si  el estado de una o más subopciones es diferente de las demás .

En este ejemplo, registramos los ingredientes recopilados para una receta. Cuando marca o desmarca la casilla de verificación de un ingrediente, una función de JavaScript verifica la cantidad total de ingredientes marcados:

  • Si no hay ninguno marcado, la casilla de verificación del nombre de la receta no está marcada.

  • La casilla de verificación para el nombre de la receta está en estado indeterminado (intermedio) si una o ambas están marcadas.

  • Si los tres están marcados, la casilla de verificación del nombre de la receta está marcada.

const overall = document.querySelector('#enchantment'); // 选择 id 为 enchantment 的元素
const ingredients = document.querySelectorAll('ul input'); // 选择所有 ul 元素下的 input 元素

overall.addEventListener('click', (e) => {
  e.preventDefault(); // 阻止默认事件
});

for (const ingredient of ingredients) {
  ingredient.addEventListener('click', updateDisplay); // 向每个 ingredient 元素附加 click 事件
}

function updateDisplay() {
  let checkedCount = 0; // 定义变量 checkedCount 并初始化为0
  for (const ingredient of ingredients) {
    if (ingredient.checked) { // 如果 ingredient 元素被选中
      checkedCount++; // checkedCount 加1
    }
  }

  if (checkedCount === 0) { // 如果 checkedCount 等于0
    overall.checked = false; // overall 元素未选中
    overall.indeterminate = false; // overall 元素不处于不确定状态
  } else if (checkedCount === ingredients.length) { // 如果 checkedCount 等于 ingredients 的长度
    overall.checked = true; // overall 元素被选中
    overall.indeterminate = false; // overall 元素不处于不确定状态
  } else { // 否则
    overall.checked = false; // overall 元素未选中
    overall.indeterminate = true; // overall 元素处于不确定状态
  }
}

8.7 Más pseudoclases

Estas pseudoclases están bastante bien soportadas en los navegadores modernos :

  • La pseudoclase :focus-within coincide con un elemento que ya tiene foco o contiene un elemento que ya tiene foco . Esto es útil si desea que todo el formulario se resalte de alguna manera cuando la entrada que contiene está enfocada.

  • La pseudoclase :focus-visible coincide con **elementos que se enfocan mediante la interacción del teclado (a diferencia del tacto o el mouse). ** Esto es útil si desea mostrar diferentes estilos para el enfoque del teclado versus el enfoque del mouse (u otro).

  • La pseudoclase :placeholder-shown coincide con los elementos <input> y <textarea> para los cuales se muestra el marcador de posición (es decir, el contenido del atributo del marcador de posición) porque el elemento tiene un valor vacío.

Los siguientes también son interesantes, pero aún no son compatibles con los navegadores :

  • La pseudoclase :blank puede seleccionar controles de formulario vacíos . :empty también coincide con elementos sin hijos , como <input>, pero es más general: también coincide con otros elementos vacíos como <br> y <hr> . :empty tiene un soporte de navegador razonable; la especificación de la pseudoclase :blank aún no está completa, por lo que aún no es compatible con ningún navegador.

  • La pseudoclase :user-invalid , si es compatible, será similar a :invalid pero con una mejor experiencia de usuario. Si el valor era válido cuando la entrada recibió el foco, el elemento puede coincidir con :invalid si el valor no es válido temporalmente cuando el usuario ingresa datos, pero solo coincidirá con :user-invalid cuando el elemento pierda el foco . Si el valor inicialmente no es válido, coincidirá con :invalid y :user-invalid durante toda la duración del enfoque. Similar a :invalid, dejará de coincidir con :user-invalid si el valor se vuelve válido.

9. Validación de datos del formulario

La validación de formularios nos ayuda a garantizar que los usuarios completen los datos del formulario en el formato correcto, asegurándonos de que los datos enviados permitan que nuestra aplicación funcione correctamente.

9.1 ¿Qué es la validación de datos del formulario?

Cuando envía un formulario sin ingresar información en el formato esperado, la página de registro le brindará comentarios:

  • "Este campo es obligatorio" (Este campo no se puede dejar en blanco)

  • "Ingrese su número de teléfono, su formato es: xxx-xxxx" (requiere que ingrese el formato de datos como tres números seguidos de un guión y luego de cuatro números)

  • "Ingrese una dirección de correo electrónico legal" (si los datos que ingresa no se ajustan al formato de correo electrónico "[email protected]")

  • "Su contraseña debe tener entre 8 y 30 caracteres y debe contener al menos una letra mayúscula, un símbolo y un número"

Esta es la validación del formulario . La validación de formularios se puede implementar de muchas maneras diferentes . Las formas son algo molesto.

Hay tres razones principales para la validación de datos de formularios:

  • Obtener los datos correctos en el formato correcto  : si los datos de nuestros usuarios se almacenan en el formato incorrecto, o si no ingresan la información correcta o la omiten por completo, nuestra aplicación no funcionará correctamente.

  • Proteger a nuestros usuarios: obligar a los usuarios a ingresar una contraseña segura ayuda a proteger la información de su cuenta.

  • Protegernos a nosotros mismos: hay muchas formas en que los usuarios malintencionados pueden comprometer las aplicaciones abusando de los formularios desprotegidos que contienen.

Advertencia: nunca confíe en los datos pasados ​​del cliente al servidor. Incluso si su formulario se valida correctamente y evita entradas con formato incorrecto, un usuario malintencionado aún puede alterar las solicitudes de red.

Diferentes tipos de validación de datos de formulario.

La verificación del lado del cliente
ocurre en el lado del navegador, antes de que los datos del formulario se envíen al servidor. En comparación con la verificación del lado del servidor, este método tiene una mejor experiencia de usuario y puede retroalimentar los resultados de la verificación ingresada por el usuario en tiempo real. La validación se puede subdividir en los siguientes métodos:

  • Validación de JavaScript, que es una implementación totalmente personalizable;

  • HTML5 tiene validación incorporada, que no requiere JavaScript y tiene más rendimiento, pero no es tan personalizable como JavaScript.

La validación del lado del servidor
ocurre después de que el navegador envía los datos y son recibidos por el programa del lado del servidor  ; generalmente la validación del lado del servidor ocurre antes de que los datos se escriban en la base de datos. Si los datos no pasan la validación, se devolverá un error. directamente desde el mensaje del servidor e indique al navegador exactamente dónde y por qué ocurrió el error. La validación del lado del servidor no es una experiencia de usuario tan buena como la validación del lado del cliente, porque no puede devolver un mensaje de error hasta que se envíe el formulario completo .
Pero la validación del lado del servidor es la última línea de defensa de su aplicación contra datos erróneos/maliciosos, después de lo cual los datos persistirán en la base de datos. Todos los marcos del lado del servidor actuales proporcionan validación y desinfección de datos (para que los datos sean más seguros).

En el proceso de desarrollo de proyectos reales, los desarrolladores generalmente tienden a utilizar una combinación de verificación del lado del cliente y verificación del lado del servidor para garantizar mejor la exactitud y seguridad de los datos.

9.2 Uso de la validación de datos del formulario integrado

Una nueva característica particularmente útil de HTML5 es que es posible realizar la validación de datos en la entrada del usuario sin escribir una sola línea de código de script , lo que se  logra a través del atributo de validación (en-US) del elemento de formulario . defina algunas reglas para limitar la entrada del usuario , como si se debe ingresar un cuadro de entrada, o la longitud mínima y máxima de una cadena en un cuadro de entrada, o se debe ingresar un número, dirección de correo electrónico, etc. en un cuadro de entrada; También hay patrones que los datos deben coincidir.

Cuando pasa una verificación de elemento :

  • A este elemento se le podrá aplicar un estilo especial mediante la pseudoclase CSS: valid;

  • Si el usuario intenta enviar el formulario, si no hay otros controles para evitar la acción (como JavaScript para evitar el envío), se enviarán los datos del formulario.

Si un elemento no supera la validación :

  • A este elemento se le podrá  aplicar un estilo  especial mediante la pseudoclase CSS: invalid ;

  • Si el usuario intenta enviar el formulario, el navegador muestra un mensaje de error y detiene el envío del formulario.

Restricciones de validación de elementos de entrada: inicio simple Algunos atributos requeridos
específicos de HTML5 para la validación del elemento <input> :

342eaeafe88078873e74d1c3775d548b.png

<form>
  <label for="choose">Would you prefer a banana or cherry?</label>
  <input id="choose" name="i_like" required />
  <button>Submit</button>
</form>
input:invalid {
  border: 2px dashed red;
}

input:valid {
  border: 2px solid black;
}

Validación mediante expresiones regulares
Otra función de validación comúnmente utilizada es el atributo de patrón, con expresión regular como valor.
A continuación se muestran algunos ejemplos para darle una idea básica de cómo funcionan:

  • a — coincide con un carácter a (no puede coincidir con b, aa, etc.)

  • abc: coincide con a, seguido de b y finalmente c.

  • a* — coincide con 0 o más caracteres a (+ significa coincide con al menos uno o más).

  • [^a] — coincide con un carácter, pero no puede ser a.

  • a|b — coincide con un carácter a o b.

  • [abc] — coincide con un carácter, que puede ser a, b o c.

  • [^abc] — coincide con un carácter, pero no puede ser a, b o c.

  • [az] — coincide con el rango de caracteres az y todo en minúsculas (puede usar [A-Za-z] para cubrir mayúsculas o [AZ] para restringir a mayúsculas).

  • ac——Haga coincidir el carácter a, haga coincidir cualquier carácter en el medio y haga coincidir el carácter c al final.

  • a{5} — coincide con el carácter a cinco veces.

  • a{5,7} — coincide con el carácter a de cinco a siete veces, ni más ni menos.

  • [-] — coincide con un espacio o un guión.

  • [0-9] — coincide con números que van del 0 al 9.

Puede combinarlos de forma arbitraria y especificar las diferentes partes de forma arbitraria:

  • [Ll].*k: coincide con una L mayúscula o una l minúscula, luego coincide con 0 o más caracteres de cualquier tipo y finalmente coincide con una letra k minúscula.

  • [AZ][A-Za-z' -]+:  una letra mayúscula seguida de una o más letras mayúsculas y minúsculas, guiones, apóstrofes o espacios . Esto se puede utilizar para validar nombres de ciudades o pueblos en una conversación en inglés, pero requiere que la primera letra comience con mayúscula y no incluye otros caracteres, como Manchester, Ashton-under-lyne y Bishop's Stortford del Reino Unido. .

  • [0-9]{3}[ -][0-9]{3}[ -][0-9]{4} — simplemente coincide con un número de teléfono en EE. UU.  —  tres dígitos del 0 al 9 seguidos de un espacio o guión , seguido de tres dígitos del 0 al 9 , seguido de un espacio o guión , seguido de cuatro dígitos del 0 al 9. Pero la situación real puede ser más complicada, porque algunas personas pondrán corchetes en el número. Qué, la expresión aquí es simplemente para una demostración sencilla.

Para implementar estos ejemplos, actualice el formulario de su documento html para agregar un atributo de patrón, de la siguiente manera:

4a8ce5d4e73ca2e4b61f35f031a79083.png

<form>
  <label for="choose">Would you prefer a banana or a cherry?</label>
  <input id="choose" name="i_like" required pattern="banana|cherry" />
  <button>Submit</button>
</form>

El  elemento <input> acepta uno de dos valores: la cadena "banana" o la cadena "cherry" .

Nota: Algunos tipos de elementos <input> no requieren el atributo de patrón para la validación. Al especificar un tipo de correo electrónico específico se utilizará una expresión regular que coincida con el formato del correo electrónico a verificar ( si hay varios atributos, utilice comas para separar varias direcciones de correo electrónico ). Además, el tipo de URL del campo verificará automáticamente si la entrada es un enlace legítimo.

Nota: El  elemento <textarea> no admite el atributo de patrón .

Limitar la longitud de una entrada
Todos los cuadros de texto (<input> o <textarea>) se pueden limitar en longitud utilizando los atributos minlength y maxlength.

En las entradas numéricas (es decir, <input type="number">), los atributos mínimo y máximo también proporcionan restricciones de validación. Un campo no es válido si su valor es menor que el valor del atributo mínimo o mayor que el valor del atributo máximo.

Mira otro ejemplo:

4b0239f7042f42a8e3b4d3e6f6950a07.png

<form>
  <div>
    <label for="choose">Would you prefer a banana or a cherry?</label>
    <input id="choose" name="i_like" required minlength="6" maxlength="6" />
  </div>
  <div>
    <label for="number">How many would you like?</label>
    <input type="number" id="number" name="amount" value="1" min="1" max="10" />
  </div>
  <div>
    <button>Submit</button>
  </div>
</form>

Observaciones: <input type="number"> (u otros tipos, como rango) también puede obtener un atributo de paso, que especifica el valor que el valor cambia en el proceso de aumentar o disminuir (como botones para aumentar y disminuir).

Ejemplo completo
Un ejemplo completo que muestra el uso de atributos de validación en HTML:

a338e74a578178a580f15c09fec0238c.png

<form>
  <p>
    <fieldset>
      <legend>Title<abbr title="This field is mandatory">*</abbr></legend> <!-- 标题字段的标题 -->
      <input type="radio" required name="title" id="r1" value="Mr"><label for="r1">Mr.</label> <!-- 单选按钮,选择 "Mr." -->
      <input type="radio" required name="title" id="r2" value="Ms"><label for="r2">Ms.</label> <!-- 单选按钮,选择 "Ms." -->
    </fieldset>
  </p>
  <p>
    <label for="n1">How old are you?</label> <!-- 年龄字段的标题 -->
    <!-- 这里的 pattern 属性可以用作不支持 number 类 input 浏览器的备用方法
         请注意当与数字输入框一起使用时,支持 pattern 属性的浏览器会使它默认失效。
         它仅仅是在这里用作备用 -->
    <input type="number" min="12" max="120" step="1" id="n1" name="age"
           pattern="\d+"> <!-- 数字输入框,输入年龄 -->
  </p>
  <p>
    <label for="t1">What's your favorite fruit?<abbr title="This field is mandatory">*</abbr></label> <!-- 最喜欢的水果字段的标题 -->
    <input type="text" id="t1" name="fruit" list="l1" required
           pattern="[Bb]anana|[Cc]herry|[Aa]pple|[Ss]trawberry|[Ll]emon|[Oo]range"> <!-- 文本输入框,输入最喜欢的水果 -->
    <datalist id="l1"> <!-- 列表,提供可选水果 -->
      <option>Banana</option> <!-- 香蕉 -->
      <option>Cherry</option> <!-- 樱桃 -->
      <option>Apple</option> <!-- 苹果 -->
      <option>Strawberry</option> <!-- 草莓 -->
      <option>Lemon</option> <!-- 柠檬 -->
      <option>Orange</option> <!-- 橙子 -->
    </datalist>
  </p>
  <p>
    <label for="t2">What's your e-mail?</label> <!-- 电子邮件字段的标题 -->
    <input type="email" id="t2" name="email"> <!-- 电子邮件输入框,输入电子邮件地址 -->
  </p>
  <p>
    <label for="t3">Leave a short message</label> <!-- 留言字段的标题 -->
    <textarea id="t3" name="msg" maxlength="140" rows="5"></textarea> <!-- 文本域,输入留言 -->
  </p>
  <p>
    <button>Submit</button> <!-- 提交按钮 -->
  </p>
</form>
body {
  font: 1em sans-serif; /* 字体大小为1em,字体族为sans-serif */
  padding: 0; /* 内边距为0 */
  margin: 0; /* 外边距为0 */
}

form {
  max-width: 200px; /* 最大宽度为200像素 */
  margin: 0; /* 外边距为0 */
  padding: 0 5px; /* 内边距为5像素左右,0像素上下 */
}
/* 选择了所有作为 p 元素直接子元素的 label 元素 */
p > label {
  display: block; /* 显示为块级元素 */
}

input[type="text"],
input[type="email"],
input[type="number"],
textarea,
fieldset {
  /* 需要在基于 WebKit 的浏览器上对表单元素进行恰当的样式设置 */
  -webkit-appearance: none; /* 取消默认外观 */

  width: 100%; /* 宽度为100% */
  border: 1px solid #333; /* 边框为1像素宽,实线,颜色为深灰色 */
  margin: 0; /* 外边距为0 */

  font-family: inherit; /* 继承父元素的字体族 */
  font-size: 90%; /* 字体大小为90% */

  -moz-box-sizing: border-box; /* 在 Firefox 浏览器中,盒模型为border-box */
  box-sizing: border-box; /* 盒模型为border-box */
}

input:invalid {
  box-shadow: 0 0 5px 1px red; /* 阴影为红色,向右下偏移5像素,模糊半径为1像素 */
}

input:focus:invalid {
  outline: none; /* 取消轮廓线 */
}

Mensajes de error personalizados
Cada vez que enviamos datos de formulario no válidos, el navegador siempre mostrará un mensaje de error. Pero la información que se muestra depende del navegador que esté utilizando.

Estos errores generados automáticamente tienen dos desventajas :

  • No existe ningún estándar para que CSS cambie la apariencia de sus interfaces.

  • Esto depende del entorno del navegador que estén utilizando y significa que es posible que reciba un mensaje de error en otro idioma en una página en este idioma .

    521e1aa26e1c2b5e022076ad6debdb1d.png

Para personalizar la apariencia y el texto de estos mensajes, debe usar JavaScript ; HTML y CSS no se pueden usar para cambiarlos.

HTML5 proporciona  una API de validación de restricciones  para detectar y personalizar el estado de los elementos del formulario . Puede cambiar el texto del mensaje de error:
vea un ejemplo:

d448a790c2b828cdad6bbeb05ace9e62.png

var email = document.getElementById("mail"); // 获取 id 为 "mail" 的元素

email.addEventListener("input", function (event) { // 为 email 元素添加 input 事件监听器
  if (email.validity.typeMismatch) { // 如果 email 元素的值不符合类型要求
    email.setCustomValidity("I expect an e-mail, darling!"); // 设置自定义验证信息
  } else { // 否则
    email.setCustomValidity(""); // 清除自定义验证信息
  }
});

9.3 Validar formularios con JavaScript

Si desea controlar la apariencia de los mensajes de error nativos , o si desea trabajar con navegadores que no admiten la validación de formularios integrada de HTML, debe utilizar Javascript.

API de validación de restricciones
Cada vez más navegadores admiten la API de validación de restricciones, y esto se está volviendo gradualmente más confiable.
Estas API constan de grupos de métodos y propiedades que se pueden invocar en interfaces de elementos de formulario específicos :

  • ElementoBotónHTML

  • HTMLFieldSetElemento

  • Elemento de entrada HTML

  • HTMLOutputElement (es-es)

  • HTMLSelectElemento

  • HTMLTextAreaElemento

Propiedades y API de validación de restricciones

Atributos describir
mensaje de validación Un mensaje localizado que describe la información textual cuando el elemento no cumple las condiciones de validación (si corresponde) . Si no es necesario validar el elemento (willValidate es falso) o el valor del elemento cumple con las condiciones de validación, es una cadena vacía.
validez Un objeto ValidityState que describe el estado de validación del elemento . Consulte el artículo sobre posibles estados de verificación para obtener más detalles.
validez.customError Devuelve verdadero si el elemento tiene un conjunto de errores personalizado ; de lo contrario, devuelve falso.
validez.patrónNo coincide Devuelve verdadero si el valor del elemento no coincide con la expresión regular establecida; de lo contrario, devuelve falso. Cuando esta propiedad es verdadera, el elemento accederá a la pseudoclase CSS: no válida.
validez.rangoDesbordamiento Devuelve verdadero si el valor del elemento es mayor que el valor máximo establecido; de lo contrario, devuelve falso. Cuando esta propiedad es verdadera, el elemento accederá a la pseudoclase CSS: no válida.
validez.rangoUnderflow Devuelve verdadero si el valor del elemento está por debajo del valor mínimo establecido; de lo contrario, devuelve falso. Cuando esta propiedad es verdadera, el elemento accederá a la pseudoclase CSS: no válida.
validez.pasoNo coincide Devuelve verdadero si el valor del elemento no se ajusta a las reglas del atributo de paso; de lo contrario, devuelve falso. Cuando esta propiedad es verdadera, el elemento accederá a la pseudoclase CSS: no válida.
validez.demasiado larga Devuelve verdadero si el valor del elemento excede la longitud máxima establecida; de lo contrario, devuelve falso. Cuando esta propiedad es verdadera, el elemento accederá a la pseudoclase CSS: no válida.
validez.tipoNo coincide Devuelve verdadero si el valor del elemento tiene un error de sintaxis ; de lo contrario, devuelve falso. Cuando esta propiedad es verdadera, el elemento accederá a la pseudoclase CSS: no válida.
validez.valida Devuelve verdadero si el valor del elemento no tiene problema de validación, en caso contrario devuelve falso. Cuando esta propiedad es verdadera, el elemento accederá a la pseudoclase CSS :válida; de lo contrario, accederá a la pseudoclase CSS :inválida.
validez.valorFalta Devuelve verdadero si el elemento tiene el atributo requerido establecido y el valor está vacío ; de lo contrario, devuelve falso. Cuando esta propiedad es verdadera, el elemento accederá a la pseudoclase CSS: no válida.
validará Devuelve verdadero si el elemento se validará al enviar el formulario ; falso en caso contrario.

Métodos de API de validación de restricciones

método describir
verificarValidez() Devuelve verdadero si el valor del elemento no tiene problema de validación, en caso contrario devuelve falso. Este método activa el evento no válido si falla la validación del elemento .
HTMLFormElement.reportValidity() Devuelve verdadero si el elemento o sus controles de subelemento cumplen con las restricciones de validación. Cuando es falso, se genera el evento no válido que se puede deshacer para cada elemento no válido y se informan los errores de validación al usuario.
setCustomValidity(mensaje) Agrega un mensaje de error personalizado al elemento ; si se establece un mensaje de error personalizado y el elemento se considera no válido, se muestra el error especificado. Esto le permite utilizar código JavaScript para crear errores de validación en lugar de lo que proporciona la API de validación de restricciones estándar. Estos mensajes personalizados se mostrarán cuando se informen errores al usuario. Si el parámetro está vacío, borre el error personalizado.

Para navegadores más antiguos , se pueden usar polyfills (como Hyperform) para compensar su falta de soporte para API de validación de restricciones . Ahora que ya estás usando JavaScript, usar polyfills en el diseño e implementación de tu sitio web o aplicación web no es engorroso.

Ejemplo de uso de la API de validación de restricciones
Utilice esta API para crear mensajes de error personalizados.

<form novalidate> <!-- 表单,禁用浏览器默认验证 -->
  <p>
    <label for="mail"> <!-- 标签,与 id 为 "mail" 的元素关联 -->
      <span>Please enter an email address:</span> <!-- 提示文本 -->
      <input type="email" id="mail" name="mail" /> <!-- 电子邮件输入框 -->
      <span class="error" aria-live="polite"></span> <!-- 错误信息显示区域 -->
    </label>
  </p>
  <button>Submit</button> <!-- 提交按钮 -->
</form>

Los formularios utilizan  el atributo novalidate para desactivar la validación automática del navegador , lo que nos permite controlar la validación del formulario mediante scripts .
Esto no prohíbe la compatibilidad con la API de validación de restricciones ni el uso de las siguientes pseudoclases CSS: : valid, :invalid, :in-range, :out-of-range  .

El atributo aria-live (en-US) garantiza que nuestros mensajes de error personalizados se mostrarán a todos, incluidos aquellos que utilizan tecnologías de asistencia como lectores de pantalla.

Los siguientes estilos CSS hacen que nuestro formulario y su resultado de error parezcan más atractivos:

/* 仅为了使示例更好看 */
body {
  font: 1em sans-serif; /* 字体大小为1em,字体族为sans-serif */
  padding: 0; /* 内边距为0 */
  margin: 0; /* 外边距为0 */
}

form {
  max-width: 200px; /* 最大宽度为200像素 */
}

p * {
  display: block; /* 显示为块级元素 */
}

input[type="email"] {
  -webkit-appearance: none; /* 取消默认外观 */

  width: 100%; /* 宽度为100% */
  border: 1px solid #333; /* 边框为1像素宽,实线,颜色为深灰色 */
  margin: 0; /* 外边距为0 */

  font-family: inherit; /* 继承父元素的字体族 */
  font-size: 90%; /* 字体大小为90% */

  -moz-box-sizing: border-box; /* 在 Firefox 浏览器中,盒模型为border-box */
  box-sizing: border-box; /* 盒模型为border-box */
}
/* 校验失败的元素样式 */
input:invalid {
  border-color: #900; /* 边框颜色为深红色 */
  background-color: #fdd; /* 背景颜色为浅红色 */
}

input:focus:invalid {
  outline: none; /* 取消轮廓线 */
}
/* 错误消息的样式 */
.error {
  width: 100%; /* 宽度为100% */
  padding: 0; /* 内边距为0 */

  font-size: 80%; /* 字体大小为80% */
  color: white; /* 文本颜色为白色 */
  background-color: #900; /* 背景颜色为深红色 */
  border-radius: 0 0 5px 5px; /* 边框圆角半径,左上角和右上角为0,左下角和右下角为5像素 */

  -moz-box-sizing: border-box; /* 在 Firefox 浏览器中,盒模型为border-box */
  box-sizing: border-box; /* 盒模型为border-box */
}

.error.active {
  padding: 0.3em; /* 内边距为0.3em */
}

El siguiente código JavaScript muestra cómo configurar la verificación de errores personalizada:

// 有许多方式可以获取 DOM 节点;在此我们获取表单本身和
// email 输入框,以及我们将放置错误信息的 span 元素。

var form = document.getElementsByTagName("form")[0];
var email = document.getElementById("mail");
var error = document.querySelector(".error");

email.addEventListener(
  "input",
  function (event) {
    // 当用户输入信息时,校验 email 字段
    if (email.validity.valid) {
      // 如果校验通过,清除已显示的错误消息
      error.innerHTML = ""; // 重置消息的内容
      error.className = "error"; // 重置消息的显示状态
    }
  },
  false,
);
form.addEventListener(
  "submit",
  function (event) {
    // 当用户提交表单时,校验 email 字段
    if (!email.validity.valid) {
      // 如果校验失败,显示一个自定义错误
      error.innerHTML = "I expect an e-mail, darling!";
      error.className = "error active";
      // 还需要阻止表单提交事件,以取消数据传送
      event.preventDefault();
    }
  },
  false,
);

0c1e6cd9c7feb2a5eac76f46fec9a79f.png

La API de validación de restricciones le brinda una poderosa herramienta para manejar la validación de formularios, brindándole mucho más control sobre su interfaz de usuario del que puede obtener solo con HTML y CSS.

Validación de formulario cuando no se utiliza la API integrada
A veces, por ejemplo, con navegadores antiguos o widgets personalizados (en-US), no puede (o no quiere) utilizar la API de validación de restricciones.
Puede utilizar JavaScript para validar su formulario. La validación de formularios es más una cuestión de interfaz de usuario que una validación de datos reales.
¿Qué tipo de validación debo realizar?
Debe determinar cómo validar sus datos: manipulación de cadenas, conversión de tipos, expresiones regulares, etc.
¿Qué debo hacer si falla la validación del formulario?
Tienes que decidir cómo debe comportarse el formulario: ¿el formulario envía datos? ¿Está resaltado el campo incorrecto? ¿Se muestra algún mensaje de error?
¿Cómo ayudar a los usuarios a corregir datos no válidos?
Debe brindarles asesoramiento previo para que sepan cuál es la entrada esperada y mensajes de error claros.

Ejemplo sin API de validación de restricciones

<!--我们只是关闭了 HTML 校验功能。-->
<form> 
  <p>
    <label for="mail"> <!-- 标签,与 id 为 "mail" 的元素关联 -->
      <span>Please enter an email address:</span> <!-- 提示文本 -->
      <input type="text" class="mail" id="mail" name="mail" /> <!-- 文本输入框,输入电子邮件地址 -->
      <span class="error" aria-live="polite"></span> <!-- 错误信息显示区域 -->
    </label>
  </p>

  <p>
    <button type="submit">Submit</button> <!-- 提交按钮  某些旧版浏览器需要将“button”元素上的“type”属性显式设置为“submit” -->
  </p>
</form>

El CSS tampoco necesita muchos cambios, sólo necesitamos convertir la pseudoclase :invalid en una clase real y evitar el uso de selectores de atributos que no funcionan con Internet Explorer 6.

/* 校验失败的元素样式 */
input.invalid {
  border-color: #900;
  background-color: #fdd;
}

input:focus.invalid {
  outline: none;
}

El código JavaScript ha cambiado significativamente y requiere más trabajo:

// 使用旧版浏览器选择 DOM 节点的方法较少
var form = document.getElementsByTagName("form")[0]; // 获取第一个 form 元素
var email = document.getElementById("mail"); // 获取 id 为 "mail" 的元素
// 以下是在 DOM 中访问下一个兄弟元素的技巧
// 这比较危险,很容易引起无限循环
// 在现代浏览器中,应该使用 element.nextElementSibling
var error = email;
while ((error = error.nextSibling).nodeType != 1); // 获取 email 元素后面的第一个元素节点

var emailRegExp =
  /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/; // 定义电子邮件正则表达式
// 许多旧版浏览器不支持 addEventListener 方法
// 这只是其中一种简单的处理方法
function addEvent(element, event, callback) { // 定义 addEvent 函数,用于添加事件监听器
  var previousEventCallBack = element["on" + event]; // 获取元素原有的事件监听器
  element["on" + event] = function (e) { // 设置元素的新事件监听器
    var output = callback(e); // 调用回调函数
    
    if (output === false) return false; // 如果回调函数返回 false,则阻止默认事件和冒泡// 返回 `false` 来停止回调链,并中断事件的执行

    if (typeof previousEventCallBack === "function") { // 如果原有的事件监听器是函数
      output = previousEventCallBack(e); // 调用原有的事件监听器
      if (output === false) return false; // 如果原有的事件监听器返回 false,则阻止默认事件和冒泡
    }
  };
}
// 现在我们可以重构字段的约束校验了
// 由于不使用 CSS 伪类,我们必须明确地设置 valid 或 invalid 类到 email 字段上
addEvent(window, "load", function () { // 页面加载完成后执行以下代码
  var test = email.value.length === 0 || emailRegExp.test(email.value); // 检查 email 元素的值是否为空或符合正则表达式

  email.className = test ? "valid" : "invalid"; // 根据检查结果设置 email 元素的类名
});
// 处理用户输入事件
addEvent(email, "input", function () { // 当 email 元素的值改变时执行以下代码
  var test = email.value.length === 0 || emailRegExp.test(email.value); // 检查 email 元素的值是否为空或符合正则表达式
  if (test) { // 如果检查结果为真
    email.className = "valid"; // 设置 email 元素的类名为 "valid"
    error.innerHTML = ""; // 清空错误信息显示区域的内容
    error.className = "error"; // 设置错误信息显示区域的类名为 "error"
  } else { // 否则
    email.className = "invalid"; // 设置 email 元素的类名为 "invalid"
  }
});
// 处理表单提交事件
addEvent(form, "submit", function () { // 当表单提交时执行以下代码
  var test = email.value.length === 0 || emailRegExp.test(email.value); // 检查 email 元素的值是否为空或符合正则表达式

  if (!test) { // 如果检查结果为假
    email.className = "invalid"; // 设置 email 元素的类名为 "invalid"
    error.innerHTML = "I expect an e-mail, darling!"; // 设置错误信息显示区域的内容
    error.className = "error active"; // 设置错误信息显示区域的类名为 "error active"
    return false; // 阻止表单提交
  } else { // 否则
    email.className = "valid"; // 设置 email 元素的类名为 "valid"
    error.innerHTML = ""; // 清空错误信息显示区域的内容
    error.className = "error"; // 设置错误信息显示区域的类名为 "error"
  }
});

ddf61b3a7df1a4acf1ffbb906137c629.png

No es difícil crear su propio sistema de verificación. La parte difícil es hacerlo lo suficientemente genérico como para usarlo en todas las plataformas y en cualquier forma que pueda crear.
Hay muchas bibliotecas disponibles para realizar la validación de formularios ; no deberías dudar en utilizarlas. Aquí hay unos ejemplos:

  • Biblioteca independiente (implementación nativa de Javascript):

    • Validar.js

  • Complemento jQuery:

    • Validación

    • Válido8

Validación remota
Este tipo de validación es necesaria cuando los datos ingresados ​​por el usuario están vinculados con datos adicionales almacenados en el lado del servidor de aplicaciones.
Una aplicación de ejemplo sería un formulario de registro , donde necesita un nombre de usuario. Para evitar duplicaciones, es mucho mejor realizar una solicitud AJAX para verificar la disponibilidad del nombre de usuario que hacer que el usuario envíe datos y luego devuelva un mensaje de error porque el formulario está duplicado.
Realizar tal control requiere algunas precauciones :

  • Requiere una API y algunos datos para estar expuestos ; debe asegurarse de que no sean datos confidenciales .

  • El retraso de la red requiere que se realice una validación asincrónica,  lo que requiere algo de trabajo en la interfaz de usuario para garantizar que los usuarios no sean bloqueados si la validación no se realiza correctamente.

10. Enviar datos del formulario

¿Qué sucede cuando un usuario envía un formulario? ¿Adónde van los datos y qué hacer con ellos cuando llegan? También analizamos algunos problemas de seguridad relacionados con el envío de datos de formularios.

10.1 ¿A dónde van los datos?

Arquitectura Cliente/Servidor
Un cliente (normalmente un navegador web) envía una solicitud a un servidor (principalmente un servidor web como Apache, Nginx, IIS, Tomcat), utilizando el protocolo HTTP. Los servidores utilizan el mismo protocolo para responder solicitudes.

c855783211cd2318ac831bd7ce3d40f7.png

Del lado del cliente, los formularios HTML no son más que una forma cómoda y fácil de usar de configurar solicitudes HTTP para enviar datos al servidor . Esto permite al usuario proporcionar información pasada en la solicitud HTTP.

Del lado del cliente: definir cómo enviar datos
El elemento <form> define cómo enviar datos. Todas sus propiedades son para que usted configure la solicitud que se envía cuando el usuario hace clic en el botón enviar. Los dos atributos más importantes son la acción y el método .

atributo de acción
Este atributo define dónde enviar los datos . Su valor debe ser una URL válida. Si no se proporciona este atributo, los datos se enviarán a la URL de la página que contiene este formulario.
En este ejemplo, los datos se envían a una URL absoluta: http://foo.com:

<form action="http://foo.com">…</form>

Aquí utilizamos URL relativas : los datos se envían a una URL diferente en el servidor.

<form action="/somewhere_else">…</form>

En ausencia de atributos, los datos del <formulario> se envían a la misma página donde aparece el formulario de la siguiente manera :

<form>…</form>

Muchas páginas antiguas utilizan la siguiente notación para indicar que los datos deben enviarse a la misma página que contiene el formulario; esto es obligatorio porque la notación era obligatoria hasta el atributo de acción HTML5. Ahora esto ya no es necesario.

<form action="#">…</form>

Nota: Se pueden especificar URL que utilicen el protocolo HTTPS (HTTP seguro). Cuando hace esto, los datos se cifran con el resto de la solicitud, incluso si el formulario en sí está alojado en una página insegura a la que se accede mediante HTTP. Por otro lado, si el formulario está alojado en una página segura, pero especifica una URL HTTP insegura con un atributo de acción, todos los navegadores mostrarán una advertencia de seguridad al usuario cada vez que intente enviar datos, porque los datos no estar cifrado.

atributo de método
Este atributo define cómo enviar datos.
El protocolo HTTP proporciona varios métodos para realizar solicitudes: los más comunes son el método GET y el método POST.

Método GET : solicita al servidor que devuelva el recurso dado.
Considere la siguiente forma:

<form action="http://foo.com" method="get">
  <div>
    <label for="say">What greeting do you want to say?</label>
    <input name="say" id="say" value="Hi" />
  </div>
  <div>
    <label for="to">Who do you want to say it to?</label>
    <input name="to" id="to" value="Mom" />
  </div>
  <div>
    <button>Send my greetings</button>
  </div>
</form>

Dado que se utilizó el método GET, cuando envíe el formulario, verá www.foo.com/?say=Hi&to=Mom en la barra de direcciones del navegador.

bfb8fdbb73c4c2d49923b50bdf477399.png

Los datos se agregan a la URL como una serie de pares de nombre/valor.
Una vez finalizada la dirección web URL, aparece un signo de interrogación (?) seguido de pares de nombre/valor separados entre sí por un signo comercial (&).

La solicitud HTTP es la siguiente:

GET /?say=Hi&to=Mom HTTP/2.0
Host: foo.com

Método POST : el método utilizado por el navegador para comunicarse con el servidor cuando solicita una respuesta. La respuesta tiene en cuenta los datos proporcionados en el cuerpo de la solicitud HTTP.
Si se envía un formulario utilizando este método, los datos se adjuntan a el cuerpo de la solicitud HTTP.

<form action="http://foo.com" method="post">
  <div>
    <label for="say">What greeting do you want to say?</label>
    <input name="say" id="say" value="Hi" />
  </div>
  <div>
    <label for="to">Who do you want to say it to?</label>
    <input name="to" id="to" value="Mom" />
  </div>
  <div>
    <button>Send my greetings</button>
  </div>
</form>

Al enviar un formulario utilizando el método POST , no se agregan datos a la URL, la solicitud HTTP se ve así y los datos contenidos en el cuerpo de la solicitud se ven así:

POST / HTTP/2.0
Host: foo.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 13

say=Hi&to=Mom

de3d3b77f42fc17eb20daa4fd1af34ee.png

El encabezado de datos Content-Length indica el tamaño del cuerpo y el encabezado de datos Content-Type indica el tipo de recurso enviado al servidor. Discutiremos estos encabezados más adelante.

Ver solicitudes HTTP
Las solicitudes HTTP nunca se muestran al usuario.
Los datos de su formulario se mostrarán en la pestaña de red de Chrome:

  1. Presione F12

  2. Seleccione la red"

  3. Seleccionar todo"

  4. En la pestaña "Nombre", seleccione "foo.com"

  5. Seleccione "Encabezados"

e1a5029da6f6607243251b9f189b2cd9.png

Lo único que se muestra al usuario es la URL a la que se llama. Como mencionamos anteriormente, los usuarios que soliciten con GET verán los datos en su barra de URL, pero los usuarios que soliciten con POST no.

  • Si necesita enviar una contraseña (u otros datos confidenciales), nunca utilice el método GET o los datos se mostrarán en la barra de URL, lo cual es muy inseguro.

  • Si necesita enviar una gran cantidad de datos, se prefiere el método POST , porque algunos navegadores limitan el tamaño de la URL. Además, muchos servidores limitan la longitud de las URL que aceptan.

Del lado del servidor: recuperación de datos
Independientemente del método HTTP elegido, el servidor recibe una cadena y la analiza para obtener los datos como una secuencia de pares clave/valor .

Ejemplo: Python
muestra los datos enviados en una página web. Esto utilizará el marco Flask para representar plantillas, manejar envíos de datos de formularios, etc.
Esta es una  aplicación Flask simple que define dos rutas: / y /hello. Cuando el usuario visita la ruta /, la aplicación representa y devuelve la plantilla form.html. Cuando el usuario visita la ruta /hello, la aplicación recupera los valores de los campos say y to de los datos del formulario, los pasa a la plantilla Greeting.html para procesarlos y luego devuelve la plantilla procesada.

from flask import Flask, render_template, request
app = Flask(__name__)

@app.route('/', methods=['GET', 'POST']) # 定义 / 路由
def form():
    return render_template('form.html') # 渲染并返回 form.html 模板

@app.route('/hello', methods=['GET', 'POST']) # 定义 /hello 路由
def hello():
    return render_template('greeting.html', say=request.form['say'], to=request.form['to']) # 获取表单数据并渲染 greeting.html 模板

if __name__ == "__main__":
    app.run() # 运行应用程序

Las dos plantillas a las que se hace referencia en el código anterior son las siguientes:

  • form.html : el mismo formulario que vimos en la sección del método POST, pero con la acción configurada en { { url_for('hello') }} . (Esta es una plantilla Jinja2, que es básicamente HTML, pero puede incluir llamadas a código Python que ejecuta un servidor web encerrado entre llaves. url_for('hello') básicamente redirige a / cuando se envía el formulario hola  " .

  • saludo.html : esta plantilla contiene una sola línea que representa los dos fragmentos de datos que se le pasan en el momento de la renderización. Esto se hace con la función hello() vista anteriormente, que se ejecuta cuando se dirige /helloURL.

Nota: Nuevamente, este código no funcionará si solo intentas cargarlo directamente en el navegador. Python funciona un poco diferente a PHP: para ejecutar este código localmente necesita instalar Python/pip y luego instalar Flask usando pip3 install flask. En este punto, debería poder ejecutar este ejemplo usando python3 python-example.py y luego navegar hasta localhost:5000 en su navegador.

Otros lenguajes y marcos
Hay muchas otras tecnologías del lado del servidor disponibles para el procesamiento de formularios, incluidas Perl, Java, .Net, Ruby y más. Simplemente elige tu favorito y úsalo.
No es común utilizar estas técnicas directamente, ya que puede resultar complicado. Es más común utilizar una serie de marcos excelentes que facilitan el trabajo con formularios, como por ejemplo:

  • Django para Python (un poco más pesado que Flask, pero tiene más herramientas y opciones).

  • Expreso para Node.js

  • Laravel para PHP

  • Ruby sobre rieles para Ruby

  • Fénix para elixir

10.2 Caso especial: envío de archivos

El envío de archivos con formularios HTML es un caso especial.
Los archivos son datos binarios (o eso se cree que son), mientras que todos los demás datos son datos de texto.
Dado que HTTP es un protocolo de texto, existen requisitos especiales para el manejo de datos binarios.

atributo enctype Este atributo le permite especificar el valor del encabezado HTTP de tipo de contenido
en la solicitud generada cuando se envía el formulario . De forma predeterminada, su valor es application/x-www-form-urlencoded. Significa: "Estos son datos de formulario codificados como un parámetro de URL".

Si desea enviar archivos, necesita tres pasos adicionales :

  • Establezca el atributo del método en POST porque el contenido del archivo no se puede colocar en los parámetros de URL.

  • Establezca el valor de enctype en multipart/form-data porque los datos se dividirán en varias partes, donde cada archivo ocupará una parte separada y los datos de texto contenidos en el cuerpo del formulario (si también se ingresa texto en el formulario) ocuparán una parte.

  • Contiene uno o más widgets de selección de archivos que permiten a los usuarios seleccionar los archivos que se cargarán.

<form method="post" enctype="multipart/form-data">
  <div>
    <label for="file">Choose a file</label>
    <input type="file" id="file" name="myFile" />
  </div>
  <div>
    <button>Send the file</button>
  </div>
</form>

Nota: Algunos navegadores admiten el atributo múltiple de <input>, que permite seleccionar más de un archivo para cargar con un solo elemento <input>. La forma en que el servidor maneja estos archivos depende de la tecnología utilizada en el servidor. Como se mencionó anteriormente, usar un marco le hará la vida más fácil.

Para evitar abusos, muchos servidores configuran límites de tamaño de archivos y solicitudes HTTP. Es importante comprobar los permisos del administrador del servidor antes de enviar el archivo.

10.3 Problemas de seguridad comunes

Cada vez que envía datos a su servidor, debe considerar la seguridad.
Los formularios HTML son la ruta de ataque más común.
Estos problemas nunca provienen del formulario HTML en sí, sino de cómo el servidor maneja los datos .

XSS y CSRF
Las secuencias de comandos entre sitios (XSS)  y  la falsificación de solicitudes entre sitios (CSRF)  son tipos comunes de ataques que ocurren cuando  se muestran datos enviados por un usuario a este usuario o a otro usuario .

XSS permite a un atacante inyectar scripts del lado del cliente en páginas web vistas por otros usuarios.
Los ataques CSRF son similares a los ataques XSS en que inician el ataque de la misma manera (inyectando un script del lado del cliente en una página web), pero sus objetivos son diferentes. Los atacantes CSRF intentan escalar privilegios al nivel de un usuario privilegiado (como un administrador de sitio) para realizar acciones que no deberían (por ejemplo, enviar datos a un usuario que no es de confianza).
Los ataques XSS explotan la confianza de un usuario en un sitio web, mientras que los ataques CSRF explotan la confianza de un sitio web en sus usuarios.

Para evitar estos ataques, siempre debe verificar los datos que el usuario envía al servidor (si es necesario mostrarlos) y tratar de no mostrar contenido HTML proporcionado por el usuario.
Casi todos los marcos en el mercado hoy en día implementan un filtro mínimo que elimina los elementos HTML <script>, <iframe> y <object> de cualquier dato enviado por el usuario. Esto ayuda a reducir el riesgo, pero no necesariamente lo elimina.

Inyección SQL
La inyección SQL es un tipo de ataque que intenta realizar operaciones en una base de datos utilizada por un sitio web objetivo.
Esto generalmente implica enviar una solicitud SQL y esperar que el servidor la ejecute (esto suele suceder cuando el servidor de aplicaciones intenta almacenar datos enviados por el usuario). En realidad, esta es una de las principales formas de atacar un sitio web.
Las consecuencias pueden ser nefastas, desde la pérdida de datos hasta ataques que toman el control de toda la infraestructura del sitio web mediante el uso de escalada de privilegios. Esta es una amenaza muy seria y nunca debe almacenar los datos enviados por el usuario sin realizar alguna limpieza .

Inyección de encabezados HTTP e inyección de correo electrónico
Este tipo de ataque ocurre cuando su aplicación crea encabezados HTTP o correos electrónicos basados ​​en la entrada de datos del usuario en formularios.
Estos no dañarán directamente su servidor ni afectarán a sus usuarios, pero pueden provocar un problema más profundo, como el secuestro de sesión o ataques de phishing.
Estos ataques son en su mayoría silenciosos y pueden convertir su servidor en un zombi.

Paranoia: nunca confíes en tus usuarios
¿Cómo lidias con estas amenazas?
Este es un tema que va mucho más allá de esta guía, pero hay algunas reglas a tener en cuenta. El principio más importante es: nunca confíes en tus usuarios, incluido tú mismo; incluso un usuario de confianza puede ser secuestrado.

Todos los datos que llegan al servidor deben ser verificados y desinfectados. siempre así. Sin excepción.

  • Manténgase alejado de fugas de personajes potencialmente peligrosos . Los caracteres específicos que deben usarse con precaución dependen del contexto de los datos que se utilizan y de la plataforma del servidor que se utiliza, pero todos los lenguajes del lado del servidor tienen funciones correspondientes.

  • Limite la cantidad de datos ingresados ​​y permita solo los datos necesarios.

  • Cargas de archivos en sandbox  (almacenelos en diferentes servidores y solo permita el acceso a los archivos a través de diferentes subdominios, o mejor aún, a través de nombres de dominio completamente diferentes).

10.4 Conclusión

Enviar datos de formularios es fácil, pero proteger su solicitud es complicado.
Los desarrolladores front-end no son quienes deben definir el modelo de seguridad de los datos.
Como veremos, es posible realizar una validación de datos del lado del cliente (en-US), pero el servidor no puede confiar en esta validación porque no puede saber realmente qué le pasó al cliente.

El fin

Supongo que te gusta

Origin blog.csdn.net/cxyhjl/article/details/132267925
Recomendado
Clasificación