我以为后端就是web后端,后来我才知道这叫服务(器)端。
我以为后端就是黑窗程序,现在我明白它是一种特别的存在。
从基础的dart:io开始
安装环境
参考flutter环境的安装,flutter会自带的安装上dart最新版本
项目构建
作为一个flutter项目,你将会执行以下命令:
flutter create projuct_name --org com.xxxdomain -a kotlin -i swift --version 0.0.1 --description "this is a flutter projuct description."
一般不会真的输入完整的命令,这里解释一下
`create` 后面默认带了一个 `--project-name` 的参数用于指定项目名字,所以这里直接跟了一个 `projuct_name` ,注意:这个项目名一定是符合dart的包名的格式的蛇形命名法
`--org` 后跟域名,最好符合安卓软件包名规范。一般会指定域名,默认是 `com.example`
`-a -i` 用于指定安卓和iOS下的技术栈,可以通过--help查看默认类型,然后根据需求来指定技术栈。
`--version` 默认是 1.0.0 但是我喜欢从 0.0.1 开始
`--description` 后期可以改,没有必要在这里写
所以最后只剩下
flutter create projuct_name --org com.lilua --version 0.0.1
那么作为一个dart项目,也是很乖巧的和flutter神似,这是我没想到,但是又在情理之中的。
dart create projuct_name
并且dart的默认不带版本号,可以自己在 pubspec.yaml
文件中去设置
执行一个dart项目
dart run
或者单独执行某一个dart文件
dart bin/xx_module.dart
调试dart项目
dart是一个支持JIT的语言,可以实时热更新,也可以AOT编译好了再执行,提高运行效率。
参考https://www.jianshu.com/p/9567f798a353可以得到一个服务端热重载的实例。
调试和其他语言无异。打断点然后debug即可。
服务端 hello wold
将以下代码复制到main.dart里替换原来的代码。
import 'dart:io';
void main() async {
var requestServer = await HttpServer.bind(InternetAddress.loopbackIPv4, 8080);
print('监听 localhost 地址,端口号为${requestServer.port}');
//监听请求
await for (HttpRequest request in requestServer) {
//监听到请求后response回复它一个Hello World!然后关闭这个请求
var httpResponse = request.response..write('Hello World!');
await httpResponse.close();
}
}
然后在浏览器中输入 http://localhost:8080/ 就可以看到我们的第一个后端程序结果。
原理
一个简单的请求做完了,我们来看看发生了什么
从main函数进来,后面跟了一个async表示这是一个异步的函数(异步自己补习吧)
通过 HttpServer.bind
来绑定一个本地的8080端口作为请求的路口。
通过await for来解决异步获取到的每一个请求,他们会装在 requestServer
里,一个个的拿给 request
做请求的回复。
执行close结束请求。建议直接在拿到结果后直接切断请求,不要挂着导致多次请求堆叠起来。
(不明白的,直接评论区见,反正我没考虑零基础,毕竟没有出零基础的dart入门)
注意事项
尽量使用自己手敲 dart run
这个不会出问题。次之,你可以使用 vscode 的 runner 但是你也看得出来那是运行单文件的。千万避免使用vscode右上角的运行按钮,到时候运行到后台还没法点退出,需要手动在任务管理器中杀掉。
做得更加安全
为了避免其他类型的请求干扰,我们手动屏蔽掉他们。
import 'dart:io';
/// 对请求分类处理
void handleMessage(HttpRequest request) {
// 方便后期维护
try {
if (request.method == 'GET') {
handleGet(request);
} else if (request.method == 'POST') {
handlePost(request);
} else {
// 返回错误的请求
request.response
..statusCode = HttpStatus.methodNotAllowed
..write('have not ${request.method} method!!!')
..close();
}
} catch (e) {
print('get a $e');
}
}
/// 单独处理post
void handlePost(HttpRequest request) {
/// 语法糖,..表示直接引用原来的对象来继续执行方法,可以连续执行多个方法。
request.response
..write('post')
..write('something')
..close();
}
/// 单独处理get
void handleGet(HttpRequest request) {
request.response
..write('get')
..close();
}
void main() async {
var requestServer = await HttpServer.bind(InternetAddress.loopbackIPv4, 8080);
//HttpServer.bind(主机地址,端口号)
//主机地址:InternetAddress.loopbackIPv4和InternetAddress.loopbackIPv6都可以监听到
print('监听 localhost地址,端口号为${requestServer.port}');
//监听请求
await for (HttpRequest request in requestServer) {
handleMessage(request);
}
}
对于请求结果的状态值:
abstract class HttpStatus {
//继续
static const int continue_ = 100;
//交换协议
static const int switchingProtocols = 101;
//可以
static const int ok = 200;
//已创建
static const int created = 201;
//认可的
static const int accepted = 202;
//非授权信息
static const int nonAuthoritativeInformation = 203;
//没有内容
static const int noContent = 204;
//重置内容
static const int resetContent = 205;
//部分内容
static const int partialContent = 206;
//多项选择
static const int multipleChoices = 300;
//永久迁移
static const int movedPermanently = 301;
//已发现
static const int found = 302;
//临时迁移
static const int movedTemporarily = 302; // Common alias for found.
//查看其它
static const int seeOther = 303;
//未修改的
static const int notModified = 304;
//使用代理
static const int useProxy = 305;
//暂时重定向
static const int temporaryRedirect = 307;
//请求失败
static const int badRequest = 400;
//没有授权
static const int unauthorized = 401;
//要求付款
static const int paymentRequired = 402;
//被禁止
static const int forbidden = 403;
//未找到
static const int notFound = 404;
//请求方法不允许
static const int methodNotAllowed = 405;
//不接受
static const int notAcceptable = 406;
//需要代理身份认证
static const int proxyAuthenticationRequired = 407;
//请求超时
static const int requestTimeout = 408;
//冲突
static const int conflict = 409;
//过去了
static const int gone = 410;
//长度要求
static const int lengthRequired = 411;
//先决条件失败
static const int preconditionFailed = 412;
//请求实体过大
static const int requestEntityTooLarge = 413;
//请求地址过长
static const int requestUriTooLong = 414;
//非支持的媒体类型
static const int unsupportedMediaType = 415;
//请求范围不可满足
static const int requestedRangeNotSatisfiable = 416;
//期望失败
static const int expectationFailed = 417;
//升级要求
static const int upgradeRequired = 426;
//内部服务器错误
static const int internalServerError = 500;
//未实现
static const int notImplemented = 501;
//网关坏了
static const int badGateway = 502;
//服务不可用
static const int serviceUnavailable = 503;
//网关超时
static const int gatewayTimeout = 504;
//http版本不支持
static const int httpVersionNotSupported = 505;
// 连接超时
static const int networkConnectTimeoutError = 599;
}
可以直接点进 HttpStatus
类里面看看它的实现,dart易学在于,官方代码注释非常漂亮。
从uri中拿到参数
例如:http://localhost:8080/?id=4234
我们修改一下 handleGet
函数
void handleGet(HttpRequest request) {
var value = request.uri.queryParameters['id'];
request.response
..write('get id is $value')
..close();
}
就是这样简单,使用 request.uri
拿到地址,使用 queryParameters
来匹配id。这样就拿到了传入的值