Web-1

作者: 吕阳 | 来源:发表于2017-11-06 16:43 被阅读25次

    Web1-1

    • 网址组成(四部分)
      协议 http, https(https 是加密的 http)
      主机 g.cn zhihu.com之类的网址
      端口 HTTP 协议默认是 80,因此一般不用填写
      路径 下面的「/」和「/question/31838184」都是路径

    ——HTTP协议——

    一个传输协议,协议就是双方都遵守的规范。
    为什么叫超文本传输协议呢,因为收发的是文本信息。
    1,浏览器(客户端)按照规定的格式发送文本数据(请求)到服务器
    2,服务器解析请求,按照规定的格式返回文本数据到浏览器
    3,浏览器解析得到的数据,并做相应处理

    请求和返回是一样的数据格式,分为4部分:
    1,请求行或者响应行
    2,Header(请求的 Header 中 Host 字段是必须的,其他都是可选)
    3,\r\n\r\n(连续两个换行回车符,用来分隔Header和Body)
    4,Body(可选)

    请求的格式,注意大小写(这是一个不包含Body的请求):
    原始数据如下
    'GET / HTTP/1.1\r\nhost:g.cn\r\n\r\n'
    打印出来如下
    GET / HTTP/1.1
    Host: g.cn

    其中
    1, GET 是请求方法(还有POST等,这就是个标志字符串而已)
    2,/ 是请求的路径(这代表根路径)
    3,HTTP/1.1 中,1.1是版本号,通用了20年

    具体字符串是 'GET / HTTP/1.1\r\nhost:g.cn\r\n\r\n'
    返回的数据如下

    HTTP/1.1 301 Moved Permanently

    Alternate-Protocol: 80:quic,p=0,80:quic,p=0

    Cache-Control: private, max-age=2592000

    Content-Length: 218

    Content-Type: text/html; charset=UTF-8

    Date: Tue, 07 Jul 2015 02:57:59 GMT

    Expires: Tue, 07 Jul 2015 02:57:59 GMT

    Location: http://www.google.cn/

    Server: gws

    X-Frame-Options: SAMEORIGIN

    X-XSS-Protection: 1; mode=block

    Body部分太长,先不贴了

    其中响应行(第一行):

    1,HTTP/1.1 是版本
    2,301 是「状态码」,参见文末链接
    3,Moved Permanently 是状态码的描述

    浏览器会自己解析
    Header部分,然后将
    Body显示成网页

    ——web服务器做什么——

    主要就是解析请求,发送相应的数据给客户端。
    例如附件中的代码(1client.py)就是模拟浏览器发送 HTTP 请求给服务器并把收到的所有信息打印出来(使用的是最底层的 socket,现阶段不必关心这种低层,web开发是上层开发)

    client

    # coding: utf-8
    
    import socket
    
    
    # socket 是操作系统用来进行网络通信的底层方案
    # 简而言之, 就是发送 / 接收数据
    
    # 创建一个 socket 对象
    # 参数 socket.AF_INET 表示是 ipv4 协议
    # 参数 socket.SOCK_STREAM 表示是 tcp 协议
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 这两个其实是默认值, 所以你可以不写, 如下
    # s = socket.socket()
    # s = ssl.wrap_socket(socket.socket())
    
    # 主机(域名或者ip)和端口
    host = 'www.baidu.com'
    port = 80
    # 用 connect 函数连接上主机, 参数是一个 tuple
    s.connect((host, port))
    
    # 连接上后, 可以通过这个函数得到本机的 ip 和端口
    ip, port = s.getsockname()
    print('本机 ip 和 port {} {}'.format(ip, port))
    
    # 构造一个 HTTP 请求
    http_request = 'GET / HTTP/1.1\r\nhost:{}\r\n\r\n'.format(host)
    # 发送 HTTP 请求给服务器
    # send 函数只接受 bytes 作为参数
    # str.encode 把 str 转换为 bytes, 编码是 utf-8
    request = http_request.encode('utf-8')
    print('请求', request)
    s.send(request)
    
    # 接受服务器的响应数据
    # 参数是长度, 这里为 1023 字节
    # 所以这里如果服务器返回的数据中超过 1023 的部分你就得不到了
    response = s.recv(1023)
    
    # 输出响应的数据, bytes 类型
    print('响应', response)
    # 转成 str 再输出
    print('响应的 str 格式', response.decode('utf-8'))
    

    http1

    import socket
    
    
    # 这个程序就是一个套路程序, 套路程序没必要思考为什么会是这样
    # 记住套路, 能用, 就够了
    # 运行这个程序后, 浏览器打开 localhost:2000 就能访问了
    #
    # 服务器的 host 为空字符串, 表示接受任意 ip 地址的连接
    # post 是端口, 这里设置为 2000, 随便选的一个数字
    host = ''
    port = 2000
    
    # s 是一个 socket 实例
    s = socket.socket()
    # s.bind 用于绑定
    # 注意 bind 函数的参数是一个 tuple
    s.bind((host, port))
    
    
    # 用一个无限循环来处理请求
    while True:
        # 套路, 先要 s.listen 开始监听
        # 注意 参数 5 的含义不必关心
        s.listen(5)
        # 当有客户端过来连接的时候, s.accept 函数就会返回 2 个值
        # 分别是 连接 和 客户端 ip 地址
        connection, address = s.accept()
    
        # recv 可以接收客户端发送过来的数据
        # 参数是要接收的字节数
        # 返回值是一个 bytes 类型
        request = connection.recv(1024)
    
        # bytes 类型调用 decode('utf-8') 来转成一个字符串(str)
        print('ip and request, {}\n{}'.format(address, request.decode('utf-8')))
    
        # b'' 表示这是一个 bytes 对象
        response = b'HTTP/1.1 200 hao\r\n\r\n<h1>Hello World!</h1>'
        # 用 sendall 发送给客户端
        connection.sendall(response)
        # 发送完毕后, 关闭本次连接
        connection.close()
    

    精简版本地客户端服务器

    • 服务器
    import socket
    
    host = ""
    port = 2000
    
    s = socket.socket()
    
    s.bind((host,port))
    print('before while')
    while True:
        print('before listen')
        s.listen(5)
        print('after listen')
        connection, address = s.accept()
        #这个request是有必要有的.否则会失败.
        request = connection.recv(1024)
    
        response = b'HTTP/1.1 200 hao\r\n\r\n<h1>Hello Yue!</h1>'
    
        connection.sendall(response)
    
        connection.close()
    
    • 客户端
    import socket
    
    host = "localhost"
    port = 2000
    
    s = socket.socket()
    s.connect((host, port))
    http_request = "GET / HTTP/1.1\r\nHost:{}\r\n\r\n".format(host)
    
    request = http_request.encode('utf-8')
    
    s.send(request)
    
    response = s.recv(1023)
    
    print('响应的 str 格式',response.decode('utf-8'))
    

    输入:print('ip and request, {}\n{}'.format(address, request.decode('utf-8')))

    输出:ip and request, ('127.0.0.1', 57243)
    GET /favicon.ico HTTP/1.1
    Host: localhost:2000
    Connection: keep-alive
    Pragma: no-cache
    Cache-Control: no-cache
    User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36
    Accept: image/webp,image/,/*;q=0.8
    Referer: http://localhost:2000/
    Accept-Encoding: gzip, deflate, sdch, br
    Accept-Language: en-US,en;q=0.8,zh-CN;q=0.6,zh;q=0.4,ja;q=0.2
    Cookie: SID=s%3Aj5EvLdf8fJbNZiOuNigTYhGDKgJkaOTT.geyhCc9aOaLLI%2B4bH0ivUxU8f5aSoWXV7sWWDzQDs1o; optimizelyEndUserId=oeu1509719645050r0.6015629543541059; _ga=GA1.1.1695961780.1490176344; _gid=GA1.1.1651571532.1510121819; Hm_lvt_dec99185042a5ffec601faced654a817=1509950985,1510121820,1510122239,1510138026; Hm_lpvt_dec99185042a5ffec601faced654a817=1510139622

    这个format函数,就是用address和request代替前面的大括号.\n是换行.
    address是元组,自带大括号.

    相关文章

      网友评论

          本文标题:Web-1

          本文链接:https://www.haomeiwen.com/subject/jvclmxtx.html