由于多种原因,您在此处尝试执行的操作将不起作用,但您无需执行任何操作 - 请参见下文。
第一个问题
根据规范,您在此处使用的 303“查看其他”重定向应始终后跟 GET(或 HEAD)请求,而不是 PUT 或其他任何内容。请参阅 RFC 7231,第 6.4.4 节:
相关部分:
303 (See Other) 状态码表示服务器是
将用户代理重定向到不同的资源,如
Location 标头字段中的 URI,旨在提供
对原始请求的间接响应。 用户代理可以执行
针对该 URI 的检索请求(如果使用,则为 GET 或 HEAD 请求
HTTP),也可能被重定向,并呈现最终结果
作为对原始请求的回答。请注意,新的 URI 在
Location头域不被认为等同于有效
请求 URI。 [强调]
第二个问题
其他流行的重定向类型 - 301“永久移动”和 302“找到”在实践中通常与规范相反就像它们是 303“查看其他”一样,因此 GET 请求是制作。
参见维基百科上的List of HTTP status codes:
这是与标准相矛盾的行业实践的示例。 HTTP/1.0 规范 (RFC 1945) 要求客户端执行临时重定向(最初的描述短语是“临时移动”),但流行的浏览器使用 303 See Other 的功能实现了 302。因此,HTTP/1.1 增加了状态码 303 和 307 来区分这两种行为。但是,一些 Web 应用程序和框架使用 302 状态代码,就好像它是 303。[强调添加]
第三个问题
有一个 307 临时重定向(从 HTTP/1.1 开始),但它明确禁止更改 HTTP 方法,因此您只能将 POST 重定向到 POST、将 PUT 重定向到 PUT 等,这有时很有用,但在这个案例 - 参见维基百科:
在这种情况下,应该使用另一个 URI 重复请求;但是,未来的请求仍应使用原始 URI。与历史上 302 的实现方式相比,在重新发出原始请求时,不允许更改请求方法。例如,应该使用另一个 POST 请求重复一个 POST 请求。
这个 307 重定向仍然不是您想要的,即使它是,据我所知,它并没有得到普遍支持,因此需要谨慎使用。
有关更多信息,另请参阅此答案:
您的选择
您可以抽象出您的控制器 - 对于任何复杂的事情,您通常都会这样做:
// controllers - usually 'required' from a different file
const update = (req, res) = {
// update date
};
const add = (req, res) => {
if (date exists) {
return update(req, res);
}
// add to database
};
router.post('/:date', add);
router.put('/:date', update);
或者您可以将控制器的部分抽象为函数。
通用控制器
另外,请注意,您可以编写通用控制器,调用每个可能在这里工作的 HTTP 方法:
router.use('/:date', (req, res) => {
});
休息
请注意,您在此处所做的不是通常的 RESTful 命名路径的方式,在您的情况下仅对新日期和更新日期使用 PUT 可能是有意义的。
与许多人的想法相反PUT 并不意味着更新。这意味着将资源(新的或不是的)放到某个 URL(如果它已经存在,则覆盖旧的)。这很像在 shell 中写这个:
echo abc > /the/path/to/file.txt
如果文件存在,它将“更新”文件,但如果不存在,它也会创建一个新文件。
例如,如果您有 /users/:id 路径,那么您使用:
- GET /users 获取用户列表
- GET /users/:id 以获取具有该 ID 的特定用户
- POST /user (not /users/:id) 以创建新用户而不提供 ID
- PUT /users/:id 覆盖现有用户或创建提供 ID 的新用户
- PATCH /users/:id 以更新具有该 ID 的用户提供的字段
在这里,据我了解,您的 :date 就像一个 ID,即。如果记录已存在,则要覆盖该记录,如果不存在则创建。 在这两种情况下,您都提供了 :date 路径组件,因此您也可以在所有情况下使用 PUT。
换句话说,您不能从一种 HTTP 方法重定向到另一种 HTTP 方法(GET 除外),但在这种情况下您不需要这样做。