
1. 表单提交
1.1 表单的作用
表单是Web开发中常见的数据收集方式, 它允许用户通过表单输入数据, 并通过提交操作将这些数据发送到服务器进行处理.
表单提交方式主要分为两大类: 传统的同步提交(也称为标准提交)和异步提交(主要通过Ajax实现).
它们在工作方式, 用户体验和数据传输等方面存在显著的差异.
开发Web应用程序的注意事项:
安全性: 无论使用哪种提交方式, 都需要考虑数据的安全性, 如防止CSRF攻击, 数据加密等.
验证: 在客户端进行基本的验证(如输入格式验证)可以提高用户体验, 但服务器端的验证是必不可少的, 以防止恶意提交.
用户体验: 提供清晰的反馈(如加载指示器, 成功/错误消息)可以提升用户体验.
1.2 请求方式
在Django中, 常用的数据提交方式主要依赖于HTTP请求的方法, 特别是GET和POST方法,.
表单提交中使用GET与POST方法的区别主要体现在以下几个方面:
* 1. 数据传输方向.
- GET: 主要用于从服务器上获取数据.
虽然名义上是'获取', 但在表单提交场景中, 它实际上是将表单数据附加到URL上发送到服务器,
但这一行为本质上仍被视为一种请求数据的方式.
- POST: 用于向服务器传送数据, 即客户端向服务器提交表单数据.
* 2. 数据传输方式.
- GET: 将表单数据附加在URL之后进行发送, 数据和表单内各个字段一一对应, 并且在URL中可以看到.
这种方式会限制数据的长度和类型, 因为URL有长度限制, 并且不是所有的数据都适合放在URL中.
- POST: 将数据放在HTTP请求的消息体中发送给服务器.
这种方式对用户是透明的, 用户看不到这个过程, 且理论上可以发送的数据量远大于GET方法.
* 3. 安全性.
- GET: 由于数据暴露在URL中, 因此安全性较低.
这可能导致敏感信息(如密码, 个人身份信息等)被泄露或被缓存, 从而增加安全风险.
- POST: 由于数据不在URL中传输, 因此安全性相对较高. 它更适合用于发送敏感信息或大量数据.
* 4. 数据量限制.
- GET: 由于URL长度的限制, GET方法传输的数据量通常较小, 一般不能超过2KB.
(但在实际应用中, 这个限制可能会因浏览器和服务器的不同而有所差异).
- POST: 理论上, POST方法传输的数据量没有限制, 但实际上可能会受到服务器配置的限制.
例如, 在IIS4中, POST请求的最大数据量可能为80KB, 在IIS5中可能为100KB, 但这些值都可以通过服务器配置进行调整.
* 5. 缓存与书签.
- GET: 由于URL中包含表单数据, 因此GET请求的结果可能会被浏览器缓存.
此外, 用户还可以将包含表单数据的URL添加到书签中, 这可能会导致安全问题或数据不一致.
- POST: POST请求的结果不会被浏览器缓存, 且用户无法将包含表单数据的请求添加到书签中.
* 6. 服务器端接收方式.
- GET: 在服务器端, 通常使用request.GET来接收GET方法提交的数据.
- POST: 在服务器端, 通常使用request.POST来接收POST方法提交的数据.
如果表单的enctype属性被设置为multipart/form-data(通常用于文件上传), 则需要使用request.Files属性来接收数据.
如果是通过Ajax使用json格式提交, 则需要使用request.body属性来获取原始数据, 后续需要手动处理.
1.3 表单属性
<form action="" method="post"> 是HTML中用于创建表单的标记的一部分.
这个标记定义了一个表单, 用户可以在其中输入数据, 然后提交给服务器处理.
action="": 这个属性指定了当表单提交时, 数据应该发送到哪里.
在这个例子中, action属性的值是空的(""), 这意味着表单数据将不会发送到任何URL.
在大多数情况下, 浏览器可能会尝试将表单数据提交回当前页面的URL(但这并不是绝对的,也不是HTML规范的要求).
在实际应用中, 会将action属性的值设置为一个服务器端脚本的URL,这个脚本进行处理.
method="post": 这个属性指定了表单数据应该如何发送到服务器. method属性有两个常用的值: GET和POST.
GET方法会将表单数据附加在URL之后发送(以?分隔URL和传输数据, 参数之间以&相连), 并且发送的数据量有限制(URL长度限制).
此外, 由于数据是附加在URL上的, 因此它会在浏览器的历史记录中留下痕迹, 并且可能会被缓存.
POST方法会将表单数据包含在表单提交的内容中发送, 不会附加在URL之后.
这意味着使用POST方法发送的数据量没有限制(实际上还是受限于服务器配置), 并且不会在URL中显示,
因此更加安全(尽管它并不能完全防止数据被拦截或篡改).
1.4 页面刷新
表单提交通常会触发页面的刷新, 这是因为它默认的行为是向服务器发送表单数据, 并请求服务器处理这些数据.
当点击表单的提交按钮时, 浏览器会收集表单中所有输入字段的值, 将它们编码成一个查询字符串(对于GET方法)或请求体(对于POST方法),
然后向表单的action属性指定的URL发送一个HTTP请求.
这个请求被发送到服务器后, 服务器上的应用程序会接收并处理这些数据.
处理完毕后, 服务器会返回一个HTTP响应, 该响应通常包含一个新的HTML页面①或重定向到另一个URL的指令.
(①: 可能是同一个页面, 但带有不同的查询参数或表单处理的结果).
浏览器接收到这个响应后, 会根据其内容加载新的页面或进行重定向, 从而导致了页面的刷新.
在表单中, 导致页面刷新的按钮行为通常与按钮的type属性有关.
type="button": 没有内置的功能(包括表单内容检查), 通常被用作自定义的按钮, 以便使用JavaScript或其他脚本语言来为它添加功能.
type="submit": 设置提交按钮, 提交表单的数据并刷新网页.
type="reset": 设置重置按钮, 清空表单的数据.
默认情况下, 如果<button>标签在HTML中没有明确设置type属性, 那么它的行为会根据浏览器的不同而有所差异.
在大多数现代浏览器中, 未设置type的<button>默认行为是submit, 这意味着它会触发表单的提交并刷新网页.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>页面刷新</title>
</head>
<body>
<form id="" action="" method="post">
<label for="username">用户名:</label>
<input type="text" id="username" name="username">
<button>提交</button>
</form>
</body>
</html>

如果表单的action属性设置为当前页面的URL, 或者未设置(默认为当前页面的URL), 那么提交表单后页面会重新加载, 即刷新页面.
用户通常可以通过浏览器上的后退按钮(或快捷键, 如Ctrl+左箭头键)返回到他们之前浏览的页面, 这个行为是浏览器内置的功能.

1.5 GET方式提交示例
编写一个GET请求提交表单数据的示例:
* 1. 编写主路由, 将请求分发到子路由.
from django.urls import path, include
urlpatterns = [
path('', include(('index.urls', 'index'), namespace='index')),
]

* 2. 编写子路由, 子路由处理请求, 调用视图函数.
from django.urls import path
from index.views import index
urlpatterns = [
path('', index, name='index'),
]

* 3. 编写视图函数处理请求, 第一次GET请求返回一个页面, 而通过表单发送的GET请求则需要从请求中获取数据.
from django.shortcuts import render, HttpResponse
def index(request):
print(request.GET)
if request.GET:
return HttpResponse('提交成功!')
return render(request, 'index.html')

* 3. 编写模板页面, 包含一个表单.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户注册</title>
</head>
<body>
<div>
<form action="" method="get">
<p>
<label for="username">用户:<input type="text" name="username"></label>
</p>
<p>
<label for="password">密码:<input type="text" name="password"></label>
</p>
<p>
<input type="submit">
<p>
</form>
</div>
</body>
</html>

* 4. 启动项目, 访问: 127.0.0.1:8000 , 在表单中填写数据并提交.

* 5. 查询终端显示的信息和提交请求后返回的页面信息.

1.6 POST方式提交示例
编写POST请求提交表单数据的示例:
* 1. 修改上面的示例的模板, 修改表单的method属性值为POST.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户注册</title>
</head>
<body>
<div>
<form action="" method="post">
<p>
<label for="username">用户:<input type="text" name="username"></label>
</p>
<p>
<label for="password">密码:<input type="text" name="password"></label>
</p>
<p>
<input type="submit">
<p>
</form>
</div>
</body>
</html>

* 2. 修改视图, 处理GET请求与POST请求.
from django.shortcuts import render, HttpResponse
def index(request):
if request.method == 'GET':
return render(request, 'index.html')
if request.method == 'POST':
print(request.POST)
return HttpResponse('提交成功!')

* 3. 启动项目, 访问: 127.0.0.1:8000 , 在表单中填写数据并提交.

* 4. 使用POST请求提交表单时会遇到'Forbidden (403)'错误: 'CSRF verification failed, Request aborted.'.
这与跨站请求伪造(Cross-Site Request Forgery, CSRF)保护机制有关.
CSRF是一种网络攻击方式, 攻击者通过诱导用户访问一个恶意网站,
该网站在后台向受害网站发送请求, 从而冒充用户执行未授权的操作.

* 5. 在任何地方添加模板语法{
% csrf_token %}.
在Django框架中, {
% csrf_token %}是一个模板标签, 用于在表单中生成一个跨站请求伪造(CSRF)保护令牌.
这个令牌是一个隐藏的表单字段, 它会自动包含在渲染的HTML中, 以确保表单的提交是来自于可信的源, 而不是通过CSRF攻击发起的.
当在Django的模板中编写表单时, 应该在表单的<form>标签内部添加{
% csrf_token %}标签.
这样, 当表单被渲染并发送到服务器时, 它会包含一个CSRF令牌, 服务器将使用这个令牌来验证请求的有效性.

* 6. 启动项目, 访问: 127.0.0.1:8000 , 在表单中填写数据并提交.

2. 同步提交
同步提交(Standard Submission): 同步提交是最常见的表单提交方式, 当用户填写完表单并点击提交按钮时,
浏览器会按照表单的action属性指定的URL, 将表单数据发送给服务器.
在发送数据的过程中, 浏览器会暂时锁定界面, 等待服务器的响应.
服务器处理完数据后, 会返回一个新的页面或刷新当前页面来显示处理结果.
特点:
- 同步性: 传统的表单提交是同步的, 即用户提交表单后, 页面会重新加载以显示服务器处理后的结果.
- 全页刷新: 表单提交会导致整个页面刷新, 这可能会中断用户的当前操作或导致页面上的其他数据丢失(用户体验可能因页面刷新而中断).
- 简单直接: 表单提交方式简单直接, 易于理解和实现, 特别适合于简单的数据收集场景.
- 应用场景: 表单提交适用于需要收集用户输入信息并将其发送到服务器进行处理的场景, 如用户注册, 登录, 提交反馈等.
实现:
HTML表单中定义action属性指定提交的目标URL.
使用method属性指定提交方法(GET或POST).
用户填写表单后, 点击提交按钮或触发表单的submit事件.
编写一个页面计算器作为示例.
* 1. 修改视图, 如果是get请求返回一个表单, 如果是post请求则获取表单的数据, 并进行计算, 最后返回页面, 计算参数, 计算结果.
在Django的QueryDict对象中, get()方法返回的是第一个值(字符串), 而getlist()方法返回的是值的完整列表(字符串列表).
from django.shortcuts import render
def index(request):
if request.method == 'GET':
return render(request, 'index.html')
else:
print(request.POST)
x = request.POST.get('x')
y = request.POST.get('y')
z = int(x) + int(y)
return render(request, 'index.html', locals())

* 2. 修改index模板.
表单中通过模板语法, 例: {
{
x }}, 判断是否填充默认值.
如果get请求访问视图, 没有为页面提供这些值, 输入框框则是空白的,
如果点击计算发送post请求访问视图, 正常填写信息的情况下, 视图为页面提供值, 输入框不在空白.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>计算器</title>
</head>
<body>
<div class="form-container">
<form action="" method="post">
<input type="text" name="x" value="{
{ x }}"> +
<input type="text" name="y" value="{
{ y }}"> =
<input type="text" name="z" value="{
{ z }}">
<input type="submit" id="button" value="计算">
</form>
</div>
</body>
</html>

* 3. 启动项目, 访问: 127.0.0.1:8000 , 返回一个空表单, 填写信息后点击按钮提交.


* 4. 在终端查看到, QueryDict字有一个键值对就是CSRF令牌信息.

* 5. 视图中重新返回视图页面, 并为输入框填充默认值.

用户填写表单后, 点击'计算'按钮, 此时, 浏览器会向服务器发送一个HTTP POST请求, 请求中包含表单数据(即x和y的值).
服务器接收到请求后, 处理数据(在这个例子中是计算x和y的和), 然后将结果(连同整个页面)返回给浏览器.
这个过程中, 浏览器会刷新页面, 以显示新的内容(包括计算结果).
由于页面需要刷新, 页面需要重新渲染, 如果表单数据很长或网络延迟较高时, 用户可能需要等待较长时间才能看到结果.
3. 异步提交
3.1 Ajax介绍
异步提交(Ajax Submission, 主要通过Ajax实现): 异步提交是通过JavaScript(特别是Ajax技术)实现的,
它允许表单数据在不重新加载整个页面的情况下发送到服务器.
Ajax请求通过XMLHttpRequest对象(或现代浏览器中的Fetch API)发送,
服务器处理完数据后, JavaScript可以接收到响应, 并动态地更新页面的部分内容, 而不是整个页面.
特点:
- 异步性: Ajax请求是异步的, 即用户可以在等待服务器响应的同时继续与页面进行交互.
- 局部更新: Ajax可以只更新页面的一部分, 而不是整个页面, 从而提高了用户体验和性能.
- 无刷新: Ajax请求不会导致页面刷新, 这对于需要频繁与服务器交互的应用来说非常有用.
应用场景: Ajax广泛应用于需要实时更新数据的应用中, 如搜索引擎的自动补全, 社交媒体的实时更新, 网页的异步表单验证等.
兼容性: 对于需要支持较老浏览器的应用, 需要注意Ajax技术的兼容性.
注意事项:
* 1. 确保服务器端的脚本能够处理接收到的数据, 并返回适当的响应.
* 2. 在生产环境中, 请确保Ajax请求是安全的, 特别是当涉及到敏感信息时, 考虑使用HTTPS.
* 3. 可以通过设置dataType属性来指定服务器返回的数据类型(如json, xml等), 这有助于jQuery正确解析响应数据.
* 4. 可以根据需要调整多个选项, 包括请求类型(type), 发送的数据(data), 是否缓存响应(cache), 超时时间(timeout)等.
实现:
使用JavaScript监听表单的submit事件, 并阻止其默认行为(即页面刷新).
使用Ajax技术(如XMLHttpRequest或Fetch API)将表单数据发送到服务器.
服务器处理完数据后, 返回JSON格式的响应数据.
JavaScript接收响应数据, 并动态地更新页面的相应部分.
在Web开发中, 视图负责将信息展示给用户.
这个展示过程可以通过多种方式实现, 包括直接渲染HTML页面和通过AJAX(Asynchronous JavaScript and XML)技术动态更新页面内容.
直接渲染HTML页面: 用户发起请求, 服务器处理请求并返回完整的HTML页面, 浏览器加载并展示这个页面.
使用AJAX请求: 用户发起AJAX请求, 服务器处理请求并返回数据(而不是完整的HTML页面), AJAX请求的回调函数接收这些数据.
后续一般会使用JavaScript动态更新页面的部分内容.
3.2 基础模板
jQuery提供了一系列简化的函数, 用于实现Ajax功能.
这些函数是对原生JavaScript Ajax功能的封装和扩展, 使开发者能够以更简洁, 更直观的方式执行Ajax请求.
下面是一个基本的模板, 展示了如何使用jQuery的$.ajax()方法来发送数据:
$.ajax({
url: 'your-server-endpoint',
type: 'POST',
dataType: 'json',
data