Dart学习笔记(24):Http Server

发表于2018-07-04 13:30 阅读(67)

在dart:io中,HttpServer实现了一个基本的HTTP协议服务器
HTTP是基于请求与响应模式的、无状态的应用层协议

本文地址:http://www.cndartlang.com/844.html

HTTP常基于TCP的连接方式
因此,可以通过HttpServer.listenOn(ServerSocket serverSocket)
来创建一个HttpServer用这种方法创建Http服务的时候
HttpServer.close并不会close ServerSocket

hello_http_server.dart

import 'dart:io';
import 'dart:convert';

main() async {
  //HttpServer对象绑定127.0.0.1的80端口
  var server = await HttpServer.bind(InternetAddress.LOOPBACK_IP_V4, 4041);
  //输出服务器地址端口
  print("Serving at ${server.address}:${server.port}");

  //HttpServer实现了Stream<HttpRequest>接口
  await for (HttpRequest request in server) {
    request.response
      /**
       * 设置ContentType
       * text/html 浏览器在获取文本后,自动调用html的解析器进行处理
       * text/plain 浏览器在获取文本后,不会对其进行处理
       *
       * 静态函数有:HTML TEXT JSON BINARY
       * ContentType.Text 等同 new ContentType("text", "plain", charset: "utf-8")
       */
      ..headers.contentType = new ContentType("text", "html", charset: "utf-8")
      ..write('Hello, ${await handleRequest(request) ?? 'name is null'}!')
      ..write('<br/><br/>--Dart语言中文社区')
      ..close();
  }
}

//获取表单的数据
handleRequest(HttpRequest request) async {
  //判断表单提交的方法
  switch(request.method) {
    case "GET":
    //Get方法比较简单,通过解析URI就可以得到
      return request.uri.queryParameters['name'];
    case "POST":
    /**
     * Post方法稍微麻烦一点
     * 首先,request传送的数据时经过压缩的
     * index.html中设置了utf8,因此需要UTF8解码器
     *
     * 表单提交的变量和值的字符串结构为:key=value
     * 如果表单提交了多个数据,用'&'对参数进行连接
     *
     * 对于提取变量的值,可以自行对字符串进行分析
     * 不过也有取巧的办法:
     * Uri.queryParameters(String key)能解析'key=value'类型的字符串
     *
     * Uri功能很完善,协议、主机、端口、参数都能简单地获取到
     * 其中,uri参数是用'?'连接的,例如:
     * http://www.baidu.com/s?wd=dart&ie=UTF-8
     * 因此,为了Uri类能正确解析,需要在表单数据字符串前加'?'
     */
      String strRaw = await request.transform(UTF8.decoder).join("&");
      String strUri = "?" + Uri.decodeComponent(strRaw);
      return Uri.parse(strUri).queryParameters['name'];
    default:
      return null;
  }
}

web/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Note 24</title>
</head>
<body>
    <form action="http://localhost:4041" method="post">
        <input type="text" name="name"/>
        <input type="submit" value="发送">
    </form>
</body>
</html>

运行结果:




现实中的服务器并不是输出Hello World这么简单
还需要对流程进行控制,也就是路由功能
我们可以对HttpRequest.uri进行分析
当然,route包提供了更简洁的接口

routing_requests.dart

import 'dart:io';
import 'package:route/server.dart';
import 'package:route/url_pattern.dart';

/**
* UrlPattern是正则表达式的URL解析扩展类
* 用来对URI进行解析,其中参数分隔符默认为 '#'或'\'
* reverse函数可以生成对应参数的URI
*
* Examples:
*
*  var pattern = new UrlPattern(r'/app#profile/(\d+)');
*  pattern.matches('/app/profile/1234'); // true
*  pattern.matches('/app#profile/1234'); // true
*  pattern.reverse([1234], useFragment: true); // /app#profile/1234
*  pattern.reverse([1234], useFragment: false); // /app/profile/1234
*/

//查看全部文章
final postsUrl = new UrlPattern(r'/posts\/?');
//通过id查看某篇文章
final postUrl = new UrlPattern(r'/post/(\d+)\/?');

//查看全部文章请求的回调函数,如:/posts/
servePosts(req) {
  req.response.write("All blog posts");
  req.response.close();
}

//查看某篇文章的回调函数,如:/post/24
servePost(req) {
  var postId = postUrl.parse(req.uri.path)[0];
  req.response
    ..write('Blog post $postId')
    ..close();
}

//如果url不合法,返回Not found
serveNotFound(req) {
  req.response
    ..statusCode = HttpStatus.NOT_FOUND
    ..write('Not found')
    ..close();
}

main() async {
  var server = await HttpServer.bind(InternetAddress.LOOPBACK_IP_V4, 80);
  var router = new Router(server)
    /**
     * 连接HttpServer、URL表达式、回调函数
     * Router可以通过serve添加多个服务
     *
     * 但是如果UrlPattern相同,则后面监听的回调函数不会生效
     * ..serve(postUrl, method: 'GET').listen(servePost)  //有效
     * ..serve(postUrl, method: 'GET').listen(servePostTemp)  //无效
     */
    ..serve(postsUrl, method: 'GET').listen(servePosts)
    ..serve(postUrl, method: 'GET').listen(servePost)
    ..defaultStream.listen(serveNotFound);
}

运行结果: