RESTful 设计/登录或注册资源?

我正在设计一个 Web 应用程序,然后停下来思考我的 API 应该如何设计成一个 RESTful Web 服务。目前,我的大多数 URI 都是通用的,可能适用于各种 Web 应用程序:

GET  /logout   // destroys session and redirects to /
GET  /login    // gets the webpage that has the login form
POST /login    // authenticates credentials against database and either redirects home with a new session or redirects back to /login
GET  /register // gets the webpage that has the registration form
POST /register // records the entered information into database as a new /user/xxx
GET  /user/xxx // gets and renders current user data in a profile view
POST /user/xxx // updates new information about user

我有一种感觉,我在这里做了很多错误的东西后,在所以和谷歌左右。

/logout开始,可能因为我实际上没有 GET任何东西-它可能更适合于 POST请求 /logout,破坏会话,然后 GET的重定向。那么 /logout这个术语应该保留吗?

/login/register呢。我可以将 /register改为 /registration,但这并不能从根本上改变我的服务的工作方式——如果它有更深层次的问题的话。

现在我注意到,我从未公开 /user资源。也许可以利用这一点。例如,以用户 myUser为例:

foo.com/user/myUser

或者

foo.com/user

最终用户不需要在 URI 中额外的详细信息。然而,哪一个在视觉上更吸引人呢?

关于 REST 业务,我在这里注意到了一些其他的问题,但是如果可能的话,我真的希望能够得到一些关于我在这里所阐述的内容的指导。

谢谢!

更新:

我还想就以下问题发表一些意见:

/user/1

/user/myUserName
104818 次浏览

我建议使用类似于 twitter 的用户帐户 URL,其中用户帐户 URL 类似于 foo.com/myUserName,就像你可以通过 URL https://twitter.com/joelbyler访问我的 twitter 帐户一样

我不同意注销需要一个 POST。作为 API 的一部分,如果您打算维护一个会话,那么 UUID 形式的会话 ID 可以用来跟踪用户并确认正在执行的操作已被授权。然后,即使是 GET 也可以将会话 ID 传递给资源。

简而言之,我建议你保持它的简单性,网址应该简短易记。

我将简单地从我为客户集成各种 REST Web 服务的经验谈一谈,无论它是用于移动应用程序,还是用于服务器到服务器的通信,以及为其他用户构建 REST API。以下是我从其他人的 REST API 以及我们自己构建的 API 中收集到的一些观察结果:

  • 当我们说 API 时,它通常指的是一组编程接口,而不是表示层。REST 也是以数据为中心的,而不是表示驱动的。也就是说,大多数 REST 以 JSON 或 XML 的形式返回数据,很少返回特定的表示层。这种特性(返回数据而不是直接的网页)赋予了 REST 进行多通道传输的能力。这意味着同样的 Web 服务可以在 HTML、 iOS、 Android 中呈现,甚至可以作为服务器到服务器的组合使用。
  • 将 HTML 和 REST 结合起来作为 URL 是非常罕见的。默认情况下,REST 是作为服务的思想,没有表示层。那些使用 Web 服务的用户需要根据自己的需要从他们调用的服务中提供数据。因此,下面的 URL 不符合我目前遇到的大多数基于 REST 的设计(也不符合那些来自 Facebook 或 Twitter 的标准)
GET  /register // gets the webpage that has the registration form
  • 继续前面的观点,基于 REST 的服务执行重定向(如下面建议的那些)也是不常见的(我还没有遇到过) :
GET  /logout   // destroys session and redirects to /
POST /login    // authenticates credentials against database and either redirects home with a new session or redirects back to /login

由于 REST 被设计为服务,因此诸如登录和注销之类的函数通常返回成功/失败结果(通常是 JSON 或 XML 数据格式) ,然后由使用者进行解释。这种解释可以包括重定向到适当的网页,正如你所提到的

  • 在 REST 中,URL 表示所采取的操作。出于这个原因,我们应该尽可能消除模棱两可的地方。虽然在您的情况下,使用具有相同路径(例如/register)的 GET 和 POST 来执行不同的操作是合法的,但是这种设计在提供的服务中引入了模糊性,并且可能会混淆服务的使用者。例如,下面介绍的 URL 对于基于 REST 的服务来说并不理想
GET  /register // gets the webpage that has the registration form
POST /register // records the entered information into database as a new /user/xxx

以上就是我所处理的一些问题,希望能给大家提供一些启示。

至于 REST 的实现,下面是我遇到的典型实现:

  • 获取/注销
    

    在后端执行注销并返回 JSON 来表示操作的成功/失败

  • POST/login
    

    向后端提交凭据。返回成功/失败。如果成功,通常它还会返回会话令牌和配置文件信息。

  • 邮递/登记
    

    向后端提交注册。返回成功/失败。如果成功登入,通常与成功登入相同,或者您可以选择将登记作为一项独立的服务

  • GET/user/xxx
    

    获取用户配置文件并返回用户配置文件的 JSON 数据格式

  • POST/user/xxx
    //重新命名为
    POST/updateUser/xxx
    

    将更新后的配置文件信息作为 JSON 格式发布,并在后端更新信息

有一点特别引人注目,那就是不使用 REST-ful: 使用 GET 请求登出。

(来自 http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_methods)

有些方法(例如 HEAD、 GET、 OPTION 和 TRACE)被定义为安全的,这意味着它们只用于信息检索,不应该改变服务器的状态。换句话说,他们不应该有副作用,除了相对无害的影响,如日志记录,缓存,服务横幅广告或增加一个网络计数器。[...]

服务器处理[ GET 请求]在技术上没有任何限制。因此,粗心或有意的编程可能会导致服务器上的重大更改。这是不鼓励的,因为它可能会给 Web 缓存、搜索引擎和其他自动代理带来问题[ ... ]

至于注销和重定向,您可以有一个发布到您的注销 URI 给出一个303响应重定向到后注销页面。

Http://en.wikipedia.org/wiki/post/redirect/get

Http://en.wikipedia.org/wiki/http_303

编辑以解决 URL 设计方面的问题:

“我如何设计我的资源?”对我来说是一个重要的问题; “我如何设计我的 URL?”是两方面的考虑因素:

如果可能的话,用户将看到的 URL 不应该太难看和有意义; 如果希望 Cookie 以请求的形式发送给某些资源,而不是其他资源,那么需要构造路径和 Cookie 路径。

如果 JRandomUser想要查看他自己的个人资料,而且你希望网址比 foo.com/user/JRandomUserfoo.com/user/(JRandom's numeric user id here)更漂亮,你可以为用户单独制作一个网址,让用户查看他们自己的信息:

GET foo.com/profile /*examines cookies to figure out who
* is logged in (SomeUser) and then
* displays the same response as a
* GET to foo.com/users/SomeUser.
*/

在这个问题上,我认为无知比智慧要容易得多,但这里有一些资源设计方面的考虑:

  1. 使用者: 哪些资源应该直接在浏览器中查看,通过 XHR 加载,或者由其他类型的客户端访问?
  2. 访问/身份: 响应是否依赖于 cookie 或引用程序?

RESTful 可以用作构造 URL 的指南,您可以使用 会议用户资源:

  • GET /session/new获取具有登录表单的网页
  • POST /session根据数据库对凭据进行身份验证
  • DELETE /session销毁会话并重定向到/
  • GET /users/new获得有注册表格的网页
  • POST /users将输入的信息作为 new/user/xxx 记录到数据库中
  • GET /users/xxx//在配置文件视图中获取并呈现当前用户数据
  • POST /users/xxx//更新关于用户的新信息

这些可以是复数或单数(我不确定哪一个是正确的)。我通常使用 /users作为用户索引页面(如预期的那样) ,使用 /sessions查看谁登录(如预期的那样)。

在 URL 中使用名称而不是数字(/users/43/users/joe)通常是出于对用户或搜索引擎更友好的愿望,而不是任何技术要求。两者都可以,但我建议你保持一致。

我认为,如果使用 register/login/logout 或 sign(in|up|out),那么使用 restful 术语就不太好。

会话不是 REST 的

  • 是的,我知道。通常使用 OAuth 完成,但是真正的会话并不是 REST 式的。您不应该有/login/logout 资源,主要是因为您不应该有会话。

  • 如果你要这样做,使它休息。资源是名词,而/login 和/logout 不是名词。我会去/会议。这使得创建和删除更加自然。

  • 会话的 POST 与 GET 很简单。如果将 user/password 作为变量发送,我将使用 POST,因为我不希望将密码作为 URI 的一部分发送。它会以日志的形式出现,并可能通过电线暴露出来。您还可能因 GET 参数限制而导致软件失败。

  • 对于 REST 服务,我通常使用基本授权或不使用授权。

创建用户

  • 它是一个资源,所以您不需要/注册。

    • POST/user-如果请求者不能指定 id,则创建一个用户
    • PUT/user/xxx-创建或更新用户,假设您事先知道 ID
    • GET/user-list x user id
    • GET/user/xxx-获取 id 为 xxx 的用户的详细信息
    • DELETE/user/xxx-使用 id xxx 删除用户
  • 使用哪种 ID 是一个很难回答的问题。你必须考虑强制唯一性,考虑重用被删除的旧 ID。例如,如果 id 将被回收(如果有可能的话) ,您不希望将这些 id 用作后端的外键。不过,您可以查找外部/内部 id 转换,以减轻后端需求。

我相信这是一种 RESTful 身份验证方法。登录时使用 HttpPut。当提供密钥时,可以使用此 HTTP 方法进行创建,并且重复调用是等幂的。对于 LogOff,在 HttpDelete方法下指定相同的路径。没有动词。适当的集合多元化。HTTP 方法支持这个目的。

[HttpPut]
[Route("sessions/current")]
public IActionResult LogIn(LogInModel model) { ... }


[HttpDelete]
[Route("sessions/current")]
public IActionResult LogOff() { ... }

如果需要,可以用电流代替有源电流。

ReST API 本身代表 REST,在这里你可以在数据库中来回传输资源的状态。

因此,每个动词都应该分配给一个资源,而在 /user/login中,似乎不能正确地将 login定义为一个资源,其中 user是实际的资源。

这就是我要说的,可能有点道理。

POST /user {userObject} -> To create user resource, i.e, Signup.
POST /user/:username {password: `${user_password}`} -> To identify the user by the username and authenticate using the password, i.e, Login.
GET /user -> To list all users from your table/collection
GET /user/:id -> To get details of a particular user (:id can be replaced with :username, or :email or the primary key you have setup for the user.)
PUT /user/:id -> To Update the user object.
DELETE /user/:id -> To delete the user object.

以上格式如下: [ HTTP 动词] /资源路径 { body (如果需要 *)}

而对于注销,同样的状态在登录时并不传输会话,而是一个 智威汤逊/AccessToken,这是一个客户端授权机制,存储在前端作为本地存储,如果在登录时没有过期,只需要删除它。

您将不会有一个注销路径,这需要在您的 API 上请求,而是得到的处理到期时间或删除在前端只。