上篇文章带大家基本了解了一下开始一个 Vapor 项目的流程,本篇紧接着来说说在所有 Web 框架中都最关键的 “路由”,因为 “路由” 模块在 Web 项目中担任很重要的角色,所以很多语言的 Web 框架都把 “路由” 抽离到框架层,从而减少开发者的工作量,一个设计得易用强大的 “路由” 系统也会给相应给框架增添不少色彩。

Web 开发中的路由这个概念简单来说就是 URL 路径到具体处理函数之间的映射,只有设定好了路由,访问者才能在浏览器根据相关 URL 规则进行页面跳转和访问,Vapor 对路由做了很多实用性设计,包括路由的构建、路由组、类型安全的路由参数、路由集合等等,希望看完本篇文章你能用 Vapor 写出一些简单的路由,我们先来看看 Vapor 最简单的路由注册。

Droplet

注册路由之前我们需要知道 Droplet 这个类,每个程序都应该有一个它的实例,控制着整个程序的生命周期,之后我们会通过 droplet 来注册路由,添加 provider,添加中间件 (middleware) 等等。 droplet 的初始化很简单,一个空程序看起来就像这样:

import Vapor
let drop = Droplet()
// your magic here
drop.run()

注册路由

注册一个最基本的路由通过对全局 Droplet 对象调用一个方法,指定路径和一个闭包来接收操作处理。

drop.get("welcome") { request in
    return "Hello"
}

我们通过调用 get() 方法来注册了一个路径为 /welcome 的路由,并返回了 “Hello” 这个字符串到浏览器,当然我们除了 get 还可以其他的标准 HTTP 方法,比如 postputpatchdeleteoptions

另外我们还可以使用 add() 方法来注册路由,以接收第一个参数 Method 作为 HTTP 方法来动态注册路由,Method 是一个枚举,包含了上述所列的 HTTP 标准方法,代码看起来是这样:

drop.add(.trace,"welcome") { request in return "Hello" }

可能你会想明明上面已经提供了对应的方法来注册路由,为什么还要多一个 add() 方法来注册路由?因为这个方法可以动态注册,并且支持一些其他不常见的方法(比如 trace)。

另外有一种关于多级路径的写法,直接使用参数分割,而不是在一个 String 参数中用 / 分开,官方推荐是这种写法,因为可以更容易写出类型安全的路由参数。

drop.get("foo","bar","baz") { request in
    return "You requested /foo/bar/baz"
}

如果想在 URL 路由中使用通配符怎么办?

app.get("anything","*") { request in
    return "Matches anything after /anything"
}

像这个例子因为用了 * 尾随参数,可以匹配到如下所有路径:

  • /anything
  • /anything/foo
  • /anything/foo/bar
  • /anything/foo/bar/baz

Request

每个路由的闭包都会有一个 Request 参数,用来获得每一个访问请求的相关内容,比如 URL 参数、HTTP Header、HTTP Body 等等,而且 Vapor 都已经为你封装好了很方便的接口来获取这些内容,甚至直接解析 JSON。

详细使用可以参考官方文档 Request 一节。

路由参数

Vapor 提倡使用类型安全的路由参数来接收数据,我们可以在路由方法中使用 Swift 类型来指定参数类型,Vapor 会在内部解析并将参数返回给闭包以供使用,非常方便。

drop.get("users",Int.self) { request,userId in return "You requested User #\(userId)" }

Swift 中处处有协议,路由参数也是如此,我们所见例子中的 Int 其实就是 Vapor 给实现了 StringInitializable 协议,当然 String 也已经默认实现。

public protocol StringInitializable {
    init?(from string: String) throws
}

Response

每个路由的闭包中可以返回三种类型的内容,ResponseResponseRepresentablethrow,你可以你可以返回自己所需的 HTTP 状态码、URL 重定向、JSON等,基本涵盖日常所需的请求返回。

Response

Response 是 Vapor 中 HTTP 模块中定义的基于 Message 的类,有很多构造方法方便我们自定义 response 返回:

// 重定向
Response(redirect: "http://vapor.codes")

// JSON
Response(status: .ok,json: JSON(["hello":"world"]))

// String
Response(body: "hello")
ResponseRepresentable

ResponseRepresentable 是一个协议,任何遵循这个协议的对象均可在路由中返回,就像之前例子中我们直接返回了字符串,就是因为 Vapor 默认给 String 实现了 ResponseRepresentable 协议,让我们可以方便的在闭包中直接返回字符串,类似的还有 JSONModel 对象。

throw

另外一大特性就是可以直接在路由中抛出异常,我们可以 throw 任何遵从 Swift.Error 协议的对象,当然 Vapor 已经为我们封装好了几个常用的 Error 来方便我们抛出异常。

drop.get("404") { request in
    throw Abort.notFound
}

当我们请求这个地址的时候一般会看到一个 Vapor 默认提供的错误页面,还挺漂亮的,如果不想用 Vapor 提供的默认错误页面,我们可以从 drop.middleware 中移除 AbortMiddleware 并添加自己的实现即可。

Abort 枚举在 Vapor 中定义如下:

public enum Abort: Swift.Error {
    case badRequest
    case notFound
    case serverError
    case custom(status: Status,message: String)
}

Status 枚举了几十个我们可能用到的 HTTP 状态码,如 200(.ok)、 301(.movedPermanently)、403(.forbidden) …

路由组

Vapor 提供了路由组的概念,通常用来集中组织一组相同前缀,添加中间件,限制主机名,或者集中管理的路由,路由组有两个类型:GroupGrouped

Group 通过一个闭包来收纳旗下所有的路由,让它们有统一的路径前缀,示例如下:

drop.group("v1") { v1 in v1.get("users") { request in // get the users } }

Grouped 原理类似,只是形式上有所变化,通过 drop.grouped() 方法返回一个 RouteGroup 对象来收纳路由。

let v1 = drop.grouped("v1")
v1.get("users") { request in
    // get the users
}

文章到此关于 Vapor 路由基本的内容也差不多都介绍完毕了,当然这里讲的可能并不全面,示例代码基本来自于官方文档(感谢 ��),下一篇准备说说 Vapor 的模版引擎 Leaf。

之前开的坑在写一个博客程序 NSPress,如果大家有兴趣欢迎讨论。

Swift Web 开发之 Vapor - 路由二的更多相关文章

  1. ios – Swift中的UIView动画不起作用,错误的参数错误

    我正在尝试制作动画并使用下面的代码.我得到“无法使用类型’的参数列表调用’animateWithDuration'(FloatLiteralConvertible,延迟:FloatLiteralConvertible,选项:UIViewAnimationoptions,动画:()–>()–>$T4,完成:(Bool)–>(Bool)–>$T5)’“错误.这意味着我使用了错误的参数.我错了.请

  2. ios – 无法识别的选择器发送到实例NSTimer Swift

    解决方法让updateTime成为一个类方法.如果它是在一个纯粹的Swift类中,你需要在@objc前面说明该方法的声明,如:

  3. 关闭iOS原生MPVolumeView音频路由菜单

    我正在使用MPVolumeView允许用户在使用我的应用程序时控制他喜欢的音频路径.该代码显示了该视图:当用户点击音频路由按钮时,会出现一个带有可用选项的菜单.问题:显示音量视图的屏幕可能需要隐藏,因为我的应用程序处理各种事件,我想同时隐藏音频路由菜单我的问题:有没有人知道是否可以手动关闭MPVolumeView的音频路由选择菜单而无需用户按下取消按钮?解决方法在iOS8上,您可以使用以下使用私有API的代码

  4. ios – 类型推断(自动类型检测)如何在swift中工作?

    LLVM如何检测变量是一个字符串?

  5. ios – Swift可选项:语言问题,还是做错了什么?

    应该有可选的类型;type是但是,如果我这样做,它的工作原理:它似乎是基本的替代,但我可能会遗漏一些语言的细微差别.谁能对此有所了解?之后就像暧昧一样,更多,这是我的解决方案:这适用于所有非对象Swift对象,包括Swift字符串,数字等.感谢Viktor提醒我String不是Swift中的对象.如果您知道值的类型,您可以替换任何?使用适当的可选类型,如String?

  6. ios – 覆盖Swift中的超类委托

    我正在开发一个包含两个UIViews的Swift(v1.2)项目.MyView和MyViewSubclass.MyView有一个委托,我想在MyViewSubclass中覆盖它作为一个子协议,类似于UITableViews有一个UITableViewDelegate,它也符合超级uiscrollviewdelegate.我的第一个想法是覆盖超类属性,但这会导致编译器错误,因为子类不能覆盖具有不同类

  7. ios – 使用捕获列表中的无主内容导致崩溃,即使块本身也不会执行

    欣赏有关如何调试此内容的任何提示或有关导致崩溃的原因的解释……

  8. ios – Swift传递封闭与Params

    目前我传递一个闭包作为一个对象的属性,该对象不接受参数并且没有返回值,如下所示:到目前为止,这工作得很好.我希望能够在设置此闭包时传入一个参数,以便在MyClass的实例中使用.我正在寻找下面的SOMETHING,虽然我确定语法不正确:我如何将参数传递给可以在MyClass中使用的闭包–即可以在属性本身的didSet部分内使用的值,如第二个示例中所示?

  9. ios – 来自UIAlertController的self.navigationController?.popViewControllerAnimated

    我是新手,但我想我已经掌握了它.这让我的进步很难过.我想要做的是当我们无法找到他的查询的相关数据时向用户抛出错误消息,然后继续将他带回到之前的ViewController.但是,我在这方面遇到了麻烦.在我添加操作的行上,我收到以下错误:’UIViewController?’不是Void的子类型我该怎么做呢?

  10. ios – 我可以在swift中将字符串转换为代码块吗?

    有没有办法将字符串转换为代码块?

随机推荐

  1. Swift UITextField,UITextView,UISegmentedControl,UISwitch

    下面我们通过一个demo来简单的实现下这些控件的功能.首先,我们拖将这几个控件拖到storyboard,并关联上相应的属性和动作.如图:关联上属性和动作后,看看实现的代码:

  2. swift UISlider,UIStepper

    我们用两个label来显示slider和stepper的值.再用张图片来显示改变stepper值的效果.首先,这三个控件需要全局变量声明如下然后,我们对所有的控件做个简单的布局:最后,当slider的值改变时,我们用一个label来显示值的变化,同样,用另一个label来显示stepper值的变化,并改变图片的大小:实现效果如下:

  3. preferredFontForTextStyle字体设置之更改

    即:

  4. Swift没有异常处理,遇到功能性错误怎么办?

    本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请发送邮件至dio@foxmail.com举报,一经查实,本站将立刻删除。

  5. 字典实战和UIKit初探

    ios中数组和字典的应用Applicationschedule类别子项类别名称优先级数据包contactsentertainment接触UIKit学习用Swift调用CocoaTouchimportUIKitletcolors=[]varbackView=UIView(frame:CGRectMake(0.0,0.0,320.0,CGFloat(colors.count*50)))backView

  6. swift语言IOS8开发战记21 Core Data2

    上一话中我们简单地介绍了一些coredata的基本知识,这一话我们通过编程来实现coredata的使用。还记得我们在coredata中定义的那个Model么,上面这段代码会加载这个Model。定义完方法之后,我们对coredata的准备都已经完成了。最后强调一点,coredata并不是数据库,它只是一个框架,协助我们进行数据库操作,它并不关心我们把数据存到哪里。

  7. swift语言IOS8开发战记22 Core Data3

    上一话我们定义了与coredata有关的变量和方法,做足了准备工作,这一话我们来试试能不能成功。首先打开上一话中生成的Info类,在其中引用头文件的地方添加一个@objc,不然后面会报错,我也不知道为什么。

  8. swift实战小程序1天气预报

    在有一定swift基础的情况下,让我们来做一些小程序练练手,今天来试试做一个简单地天气预报。然后在btnpressed方法中依旧增加loadWeather方法.在loadWeather方法中加上信息的显示语句:运行一下看看效果,如图:虽然显示出来了,但是我们的text是可编辑状态的,在storyboard中勾选Editable,再次运行:大功告成,而且现在每次单击按钮,就会重新请求天气情况,大家也来试试吧。

  9. 【iOS学习01】swift ? and !  的学习

    如果不初始化就会报错。

  10. swift语言IOS8开发战记23 Core Data4

    接着我们需要把我们的Rest类变成一个被coredata管理的类,点开Rest类,作如下修改:关键字@NSManaged的作用是与实体中对应的属性通信,BinaryData对应的类型是NSData,CoreData没有布尔属性,只能用0和1来区分。进行如下操作,输入类名:建立好之后因为我们之前写的代码有些地方并不适用于coredata,所以编译器会报错,现在来一一解决。

返回
顶部