"Create or update" 点击后退按钮时的表单行为

"Create or update" form behavior when hitting back button

我在网站上有以下工作流程:

  1. 某用户John Doe通过表1申报公司 (字段:姓名、总部所在地)
  2. John Doe 提交 (HTTP POST) 表格 1 后,他被重定向 (HTTP 302) 到公司表格 2,其中包含有关公司的其他法律信息。

问题是,如果 John Doe 在第 2 步中点击浏览器的后退按钮,他将登陆表单 1,浏览器会填充数据(使用他已经提交的值——这就是 Firefox 和主要浏览器的做法似乎可以)。

John Doe 可能会认为他可以使用此表格来更新一些信息(例如,修正公司名称中的拼写错误),而他实际上会这样做创建一个新公司,我们不知道服务器端他是想申报一家新公司还是更新他刚刚创建的公司。

您知道处理该问题的任何简单解决方案吗?

在页面加载后使用javascript/jquery脚本清空所有输入。这将防止 "updating the company".

的混淆

jQuery 看起来像这样:

$('#elementID').val('');

实际上我想到了一个技巧来获得 "create on first post, update after" 行为(就像用户认为它应该表现的那样)。

假设第 1 步表单位于 URL /create_company/。然后我可以让该页面生成一个随机代码 XXX 并重定向到 /create_company/?token=XXX。当我创建公司时,我会保存通过带有令牌 XXX 的页面创建的信息(例如,我将其保存在用户会话中,因为我们不需要永远保留该信息)以及提交表单时,如果我知道已经使用此令牌生成了一家公司,我就知道用户使用了相同的表单实例并且必须使用后退按钮,因为如果他明确要求另一家公司,则令牌会有所不同。

你怎么看? (我最初认为应该有一个更简单的解决方案,因为对于这样一个简单的问题,这似乎有点over-engineered)

这更像是一个用户体验问题。

我认为解决方案在于该表单上提供给用户的信息,以帮助他们了解他们在做什么。

例如,设置一个显示 'Create a company' 的标题,并将您的提交按钮设置为 'Create Company' 将帮助您的用户。创建公司 object 时使用唯一 ID,并将该 ID 传回相同的 URL 以执行更新。然后您应该更新您的标题和按钮,告诉用户他们正在更新而不是创建。

从这个意义上说,我认为最好使用更通用的 URL,例如 /company/company?id=12345

您也可以考虑使用 Restful API 协议来帮助您的服务器识别 CRUD 操作。 http://www.restapitutorial.com/lessons/httpmethods.html

您也可以通过manipulating the browser history处理这种情况 在加载表单 2 时,并使用查询字符串传递在提交表单 1 时生成的 CompanyId。这样您就可以实际更新公司作为用户

假设 John 提交 form1.html,将生成一个唯一的 CompanyId“1001”并重定向到 form2.html。现在在加载 form2 时,您可以使用

修改浏览器历史记录 form1.html?companyid=1001
var stateObj = { foo: "bar" };
history.pushState(stateObj, "page 1", "form1.html?companyid=1001");

现在,当用户单击后退按钮并再次提交 form1 时。您可以在查询字符串中检查 companyid 并更新公司。

没有 django 的 "routing" 部分,很难提供帮助。我可以从 express.js-router 功能中回答我的经验:

  • 你可以在 /company 上指定一个 post,这是给新用户的。
  • 您可以在 /company/:companyid 上为 post 指定另一条路由以更改表单
  • 作为来自 create-post 的响应,您可以重定向到不同的位置。

试试这个

<form autocomplete="off" ...></form>

还有一个

使用临时表或会话来存储第 1 页表单数据。如果提交第 2 页表单,请使用存储在数据库或会话中的第 1 页的临时数据。

在第 1 页和第 2 页中使用单独的键(隐藏字段)。

我认为更 user-friendly 当用户可以 return 返回到以前的表单并更新它(而不是防止所描述的行为)。 我在大多数情况下使用类似的方式来处理描述的问题:

  1. 假设用户在包含 "Create new company" 按钮的页面 /some-page 上。 当用户打开此页面时,将执行 server-side 上的特殊方法 createOrFindCompanyDraft()。此方法在数据库中创建新的公司 "draft" 记录(仅针对当前用户)。例如,草稿记录有主键 id=473。当您再次执行此方法时,它将 return 与 id=473 相同的记录(具有 "draft" 状态)。 "Draft" 记录不应显示在任何其他界面上。 "Create new company" 有 link /company/common/473.

  2. 当用户转到 /company/common/473 时,您会显示表格 1,该表格将从 "draft" 记录中填写。第一次用户会看到空表格。 从技术上讲,用户将更新现有记录,但您可以在页面上显示 "Create new company" 标题。

  3. 然后用户转到表格 2,例如 /company/legal-info/473,您为此表格创建类似的草稿记录(类似于步骤 1)。

  4. 当用户提交表单 2 时,您将从记录 id=473(以及任何相关记录)中删除 "draft" 状态。

  5. 下次用户打开页面/some-page时,将为当前用户创建新的草稿记录。

浏览器历史记录将包含:

  • /some-page
  • /company/common/473
  • /company/legal-info/473
  • /some-page2

我喜欢这种方法,因为所有表单都只更新记录。您可以多次转到 previous/next 表单(例如 "Back"/"Forward" 浏览器按钮)。您可以关闭浏览器,明天打开未完成的表格。这种方式不需要对浏览器历史记录进行任何额外操作。