minWeb框架

1.瀏覽器請求動態(tài)頁面的過程

1.png

2.WSGI

? 怎么在剛建立的web服務(wù)器上運行一個Django應(yīng)用昭伸,如何不做任何改變而適應(yīng)不同的web架構(gòu)呢?在以前巍虫,選擇python web 架構(gòu)會受制于可用的 web 服務(wù)器剃斧,反之亦然谷遂。如果架構(gòu)服務(wù)器可以協(xié)同工作超歌,那就好了:


part2-before-wsgi.png

? 但有可能面對(或者曾經(jīng)有過)下面的問題砍艾,當(dāng)要把一個服務(wù)器和一個架構(gòu)結(jié)合起來時,卻發(fā)現(xiàn)他們不是被設(shè)計成協(xié)同工作的巍举。


part2-after-wsgi (1).png

? 那么脆荷,怎么可以不修改服務(wù)器和架構(gòu)代碼而確保可以在多個架構(gòu)下運行web服務(wù)器呢懊悯?答案就是 Python Web Server Gateway Interface(或簡稱WSGI蜓谋,讀作“wizgy”,威士忌是不是更好記,哈哈哈炭分。桃焕。。)


part2-wsgi-idea.png

? WSGI允許開發(fā)者選擇web框架和web服務(wù)器分開捧毛,可以混合匹配web服務(wù)器和web框架观堂,選擇一個合適的配對。比如呀忧,可以在Gunicorn 或者 Nginx/uWSGI 或者 Waitress上運行 Django, Flask, 或 Pyramid师痕。真正的混合匹配,得益于WSGI同時支持服務(wù)器和架構(gòu):


part2-wsgi-interop.png

? web服務(wù)器必須具備WSGI接口而账,所有的現(xiàn)代Python Web框架都已具備WSGI接口胰坟,它讓你不對代碼作修改就能使服務(wù)器和特殊的web框架協(xié)同工作。WSGI由web服務(wù)器支持泞辐,而web框架允許你選擇適合自己的配對笔横,但它同樣對于服務(wù)器和框架開發(fā)者提供便利使他們可以專注于自己偏愛的領(lǐng)域和專長而不至于相互牽制。其他語言也有類似接口:java有Servlet API咐吼,Ruby 有 Rack吹缔。

3.定義WSGI接口

? WSGI接口定義非常簡單,它只要求Web開發(fā)者實現(xiàn)一個函數(shù)锯茄,就可以響應(yīng)HTTP請求涛菠。我們來看一個最簡單的Web版本的“Hello World!”:

def application(environ,start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    return 'Hello World!'

上面的application()函數(shù)就是符合WSGI標(biāo)準(zhǔn)的一個HTTP處理函數(shù),它接收兩個參數(shù):

  • environ:一個包含所有HTTP請求信息的dict對象撇吞;
  • start_response:一個發(fā)送HTTP響應(yīng)的函數(shù)俗冻。

整個application()函數(shù)本身沒有涉及到任何解析HTTP的部分,也就是說牍颈,把底層web服務(wù)器解析部分和應(yīng)用程序邏輯部分進行了分離迄薄,這樣開發(fā)者就可以專心做一個領(lǐng)域了

不過,等等煮岁,這個application()函數(shù)怎么調(diào)用讥蔽?如果我們自己調(diào)用涣易,兩個參數(shù)environ和start_response我們沒法提供,返回的str也沒法發(fā)給瀏覽器冶伞。

所以application()函數(shù)必須由WSGI服務(wù)器來調(diào)用新症。有很多符合WSGI規(guī)范的服務(wù)器。而我們此時的web服務(wù)器項目的目的就是做一個既能解析靜態(tài)網(wǎng)頁還可以解析動態(tài)網(wǎng)頁的服務(wù)器

4.web服務(wù)器-----WSGI協(xié)議---->web框架 傳遞的字典

{
    'HTTP_ACCEPT_LANGUAGE': 'zh-cn',
    'wsgi.file_wrapper': <built-infunctionuwsgi_sendfile>,
    'HTTP_UPGRADE_INSECURE_REQUESTS': '1',
    'uwsgi.version': b'2.0.15',
    'REMOTE_ADDR': '172.16.7.1',
    'wsgi.errors': <_io.TextIOWrappername=2mode='w'encoding='UTF-8'>,
    'wsgi.version': (1,0),
    'REMOTE_PORT': '40432',
    'REQUEST_URI': '/',
    'SERVER_PORT': '8000',
    'wsgi.multithread': False,
    'HTTP_ACCEPT': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    'HTTP_HOST': '172.16.7.152: 8000',
    'wsgi.run_once': False,
    'wsgi.input': <uwsgi._Inputobjectat0x7f7faecdc9c0>,
    'SERVER_PROTOCOL': 'HTTP/1.1',
    'REQUEST_METHOD': 'GET',
    'HTTP_ACCEPT_ENCODING': 'gzip,deflate',
    'HTTP_CONNECTION': 'keep-alive',
    'uwsgi.node': b'ubuntu',
    'HTTP_DNT': '1',
    'UWSGI_ROUTER': 'http',
    'SCRIPT_NAME': '',
    'wsgi.multiprocess': False,
    'QUERY_STRING': '',
    'PATH_INFO': '/index.html',
    'wsgi.url_scheme': 'http',
    'HTTP_USER_AGENT': 'Mozilla/5.0(Macintosh;IntelMacOSX10_12_5)AppleWebKit/603.2.4(KHTML,likeGecko)Version/10.1.1Safari/603.2.4',
    'SERVER_NAME': 'ubuntu'
}

5.應(yīng)用程序示例

1.文件結(jié)構(gòu)
├── web_server.py
├── Application.py
└── html
    └── index.html
    .....
2.Application.py
import time

def application(environ, start_response):
    status = '200 OK'
    response_headers = [('Content-Type', 'text/html')]
    start_response(status, response_headers)
    return str(environ) + '==Hello world from a simple WSGI application!--->%s\n' % time.ctime()
3.web_server.py
import select
import time
import socket
import sys
import re
import multiprocessing


class WSGIServer(object):
    """定義一個WSGI服務(wù)器的類"""

    def __init__(self, port, documents_root, app):

        # 1. 創(chuàng)建套接字
        self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # 2. 綁定本地信息
        self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.server_socket.bind(("", port))
        # 3. 變?yōu)楸O(jiān)聽套接字
        self.server_socket.listen(128)

        # 設(shè)定資源文件的路徑
        self.documents_root = documents_root

        # 設(shè)定web框架可以調(diào)用的函數(shù)(對象)
        self.app = app

    def run_forever(self):
        """運行服務(wù)器"""

        # 等待對方鏈接
        while True:
            new_socket, new_addr = self.server_socket.accept()
            # 創(chuàng)建一個新的進程來完成這個客戶端的請求任務(wù)
            new_socket.settimeout(3)  # 3s
            new_process = multiprocessing.Process(target=self.deal_with_request, args=(new_socket,))
            new_process.start()
            new_socket.close()

    def deal_with_request(self, client_socket):
        """以長鏈接的方式响禽,為這個瀏覽器服務(wù)器"""

        while True:
            try:
                request = client_socket.recv(1024).decode("utf-8")
            except Exception as ret:
                print("========>", ret)
                client_socket.close()
                return

            # 判斷瀏覽器是否關(guān)閉
            if not request:
                client_socket.close()
                return

            request_lines = request.splitlines()
            for i, line in enumerate(request_lines):
                print(i, line)

            # 提取請求的文件(index.html)
            # GET /a/b/c/d/e/index.html HTTP/1.1
            ret = re.match(r"([^/]*)([^ ]+)", request_lines[0])
            if ret:
                print("正則提取數(shù)據(jù):", ret.group(1))
                print("正則提取數(shù)據(jù):", ret.group(2))
                file_name = ret.group(2)
                if file_name == "/":
                    file_name = "/index.html"

            # 如果不是以py結(jié)尾的文件徒爹,認為是普通的文件
            if not file_name.endswith(".py"):

                # 讀取文件數(shù)據(jù)
                try:
                    f = open(self.documents_root+file_name, "rb")
                except:
                    response_body = "file not found, 請輸入正確的url"

                    response_header = "HTTP/1.1 404 not found\r\n"
                    response_header += "Content-Type: text/html; charset=utf-8\r\n"
                    response_header += "Content-Length: %d\r\n" % (len(response_body))
                    response_header += "\r\n"

                    response = response_header + response_body

                    # 將header返回給瀏覽器
                    client_socket.send(response.encode('utf-8'))

                else:
                    content = f.read()
                    f.close()

                    response_body = content

                    response_header = "HTTP/1.1 200 OK\r\n"
                    response_header += "Content-Length: %d\r\n" % (len(response_body))
                    response_header += "\r\n"

                    # 將header返回給瀏覽器
                    client_socket.send(response_header.encode('utf-8') + response_body)

            # 以.py結(jié)尾的文件,就認為是瀏覽需要動態(tài)的頁面
            else:
                # 準(zhǔn)備一個字典芋类,里面存放需要傳遞給web框架的數(shù)據(jù)
                env = {}
                # 存web返回的數(shù)據(jù)
                response_body = self.app(env, self.set_response_headers)

                # 合并header和body
                response_header = "HTTP/1.1 {status}\r\n".format(status=self.headers[0])
                response_header += "Content-Type: text/html; charset=utf-8\r\n"
                response_header += "Content-Length: %d\r\n" % len(response_body)
                for temp_head in self.headers[1]:
                    response_header += "{0}:{1}\r\n".format(*temp_head)

                response = response_header + "\r\n"
                response += response_body

                client_socket.send(response.encode('utf-8'))

    def set_response_headers(self, status, headers):
        """這個方法隆嗅,會在 web框架中被默認調(diào)用"""
        response_header_default = [
            ("Data", time.ctime()),
            ("Server", "ItCast-python mini web server")
        ]

        # 將狀態(tài)碼/相應(yīng)頭信息存儲起來
        # [字符串, [xxxxx, xxx2]]
        self.headers = [status, response_header_default + headers]


# 設(shè)置靜態(tài)資源訪問的路徑
g_static_document_root = "./html"
# 設(shè)置動態(tài)資源訪問的路徑
g_dynamic_document_root = "./web"

def main():
    """控制web服務(wù)器整體"""
    # python3 xxxx.py 7890
    if len(sys.argv) == 3:
        # 獲取web服務(wù)器的port
        port = sys.argv[1]
        if port.isdigit():
            port = int(port)
        # 獲取web服務(wù)器需要動態(tài)資源時,訪問的web框架名字
        web_frame_module_app_name = sys.argv[2]
    else:
        print("運行方式如: python3 xxx.py 7890 my_web_frame_name:application")
        return

    print("http服務(wù)器使用的port:%s" % port)

    # 將動態(tài)路徑即存放py文件的路徑侯繁,添加到path中胖喳,這樣python就能夠找到這個路徑了
    sys.path.append(g_dynamic_document_root)

    ret = re.match(r"([^:]*):(.*)", web_frame_module_app_name)
    if ret:
        # 獲取模塊名
        web_frame_module_name = ret.group(1)
        # 獲取可以調(diào)用web框架的應(yīng)用名稱
        app_name = ret.group(2)

    # 導(dǎo)入web框架的主模塊
    web_frame_module = __import__(web_frame_module_name)
    # 獲取那個可以直接調(diào)用的函數(shù)(對象)
    app = getattr(web_frame_module, app_name) 

    # print(app)  # for test

    # 啟動http服務(wù)器
    http_server = WSGIServer(port, g_static_document_root, app)
    # 運行http服務(wù)器
    http_server.run_forever()


if __name__ == "__main__":
    main()

6.運行

1.打開終端,輸入以下命令開始服務(wù)器
python3 web_server.py Application:app
2.打開瀏覽器訪問服務(wù)器
QQ20171101-145238@2x.png

7.min-Web框架

1.文件結(jié)構(gòu)
├── Application.py
├── templates ---存放模板文件
│   ├── center.html
│   ├── index.html
│   ├── location.html
│   └── update.html
├── static ---存放靜態(tài)的資源文件
│   ├── css
│   │   ├── bootstrap.min.css
│   │   ├── main.css
│   │   └── swiper.min.css
│   └── js
│       ├── a.js
│       ├── bootstrap.min.js
│       ├── jquery-1.12.4.js
│       ├── jquery-1.12.4.min.js
│       ├── jquery.animate-colors.js
│       ├── jquery.animate-colors-min.js
│       ├── jquery.cookie.js
│       ├── jquery-ui.min.js
│       ├── server.js
│       ├── swiper.jquery.min.js
│       ├── swiper.min.js
│       └── zepto.min.js
└── web_server.py ---mini web服務(wù)器
2.Application.py
import time
import os

template_root = "./templates"


def index(file_name):
    """返回index.py需要的頁面內(nèi)容"""
    # return "hahha" + os.getcwd()  # for test 路徑問題
    try:
        file_name = file_name.replace(".py", ".html")
        f = open(template_root + file_name)
    except Exception as ret:
        return "%s" % ret
    else:
        content = f.read()
        f.close()
        return content


def center(file_name):
    """返回center.py需要的頁面內(nèi)容"""
    # return "hahha" + os.getcwd()  # for test 路徑問題
    try:
        file_name = file_name.replace(".py", ".html")
        f = open(template_root + file_name)
    except Exception as ret:
        return "%s" % ret
    else:
        content = f.read()
        f.close()
        return content

def application(environ, start_response):
    status = '200 OK'
    response_headers = [('Content-Type', 'text/html')]
    start_response(status, response_headers)

    file_name = environ['PATH_INFO']
    if file_name == "/index.py":
        return index(file_name)
    elif file_name == "/center.py":
        return center(file_name)
    else:
        return str(environ) + '==Hello world from a simple WSGI application!--->%s\n' % time.ctime()

3.web-server.py
import select
import time
import socket
import sys
import re
import multiprocessing


class WSGIServer(object):
    """定義一個WSGI服務(wù)器的類"""

    def __init__(self, port, documents_root, app):

        # 1. 創(chuàng)建套接字
        self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # 2. 綁定本地信息
        self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.server_socket.bind(("", port))
        # 3. 變?yōu)楸O(jiān)聽套接字
        self.server_socket.listen(128)

        # 設(shè)定資源文件的路徑
        self.documents_root = documents_root

        # 設(shè)定web框架可以調(diào)用的函數(shù)(對象)
        self.app = app

    def run_forever(self):
        """運行服務(wù)器"""

        # 等待對方鏈接
        while True:
            new_socket, new_addr = self.server_socket.accept()
            # 創(chuàng)建一個新的進程來完成這個客戶端的請求任務(wù)
            new_socket.settimeout(3)  # 3s
            new_process = multiprocessing.Process(target=self.deal_with_request, args=(new_socket,))
            new_process.start()
            new_socket.close()

    def deal_with_request(self, client_socket):
        """以長鏈接的方式贮竟,為這個瀏覽器服務(wù)器"""

        while True:
            try:
                request = client_socket.recv(1024).decode("utf-8")
            except Exception as ret:
                print("========>", ret)
                client_socket.close()
                return

            # 判斷瀏覽器是否關(guān)閉
            if not request:
                client_socket.close()
                return

            request_lines = request.splitlines()
            for i, line in enumerate(request_lines):
                print(i, line)

            # 提取請求的文件(index.html)
            # GET /a/b/c/d/e/index.html HTTP/1.1
            ret = re.match(r"([^/]*)([^ ]+)", request_lines[0])
            if ret:
                print("正則提取數(shù)據(jù):", ret.group(1))
                print("正則提取數(shù)據(jù):", ret.group(2))
                file_name = ret.group(2)
                if file_name == "/":
                    file_name = "/index.html"

            # 如果不是以py結(jié)尾的文件丽焊,認為是普通的文件
            if not file_name.endswith(".py"):

                # 讀取文件數(shù)據(jù)
                try:
                    print(self.documents_root+file_name)
                    f = open(self.documents_root+file_name, "rb")
                except:
                    response_body = "file not found, 請輸入正確的url"

                    response_header = "HTTP/1.1 404 not found\r\n"
                    response_header += "Content-Type: text/html; charset=utf-8\r\n"
                    response_header += "Content-Length: %d\r\n" % (len(response_body))
                    response_header += "\r\n"

                    response = response_header + response_body

                    # 將header返回給瀏覽器
                    client_socket.send(response.encode('utf-8'))

                else:
                    content = f.read()
                    f.close()

                    response_body = content

                    response_header = "HTTP/1.1 200 OK\r\n"
                    response_header += "Content-Length: %d\r\n" % (len(response_body))
                    response_header += "\r\n"

                    # 將header返回給瀏覽器
                    client_socket.send(response_header.encode('utf-8') + response_body)

            # 以.py結(jié)尾的文件,就認為是瀏覽需要動態(tài)的頁面
            else:
                # 準(zhǔn)備一個字典咕别,里面存放需要傳遞給web框架的數(shù)據(jù)
                env = dict()
                # ----------更新---------
                env['PATH_INFO'] = file_name  # 例如 index.py

                # 存web返回的數(shù)據(jù)
                response_body = self.app(env, self.set_response_headers)

                # 合并header和body
                response_header = "HTTP/1.1 {status}\r\n".format(status=self.headers[0])
                response_header += "Content-Type: text/html; charset=utf-8\r\n"
                response_header += "Content-Length: %d\r\n" % len(response_body.encode("utf-8"))
                for temp_head in self.headers[1]:
                    response_header += "{0}:{1}\r\n".format(*temp_head)

                response = response_header + "\r\n"
                response += response_body

                client_socket.send(response.encode('utf-8'))


    def set_response_headers(self, status, headers):
        """這個方法技健,會在 web框架中被默認調(diào)用"""
        response_header_default = [
            ("Data", time.time()),
            ("Server", "ItCast-python mini web server")
        ]

        # 將狀態(tài)碼/相應(yīng)頭信息存儲起來
        # [字符串, [xxxxx, xxx2]]
        self.headers = [status, response_header_default + headers]


# 設(shè)置靜態(tài)資源訪問的路徑
g_static_document_root = "./static"
# 設(shè)置動態(tài)資源訪問的路徑
g_dynamic_document_root = "./dynamic"

def main():
    """控制web服務(wù)器整體"""
    # python3 xxxx.py 7890
    if len(sys.argv) == 3:
        # 獲取web服務(wù)器的port
        port = sys.argv[1]
        if port.isdigit():
            port = int(port)
        # 獲取web服務(wù)器需要動態(tài)資源時,訪問的web框架名字
        web_frame_module_app_name = sys.argv[2]
    else:
        print("運行方式如: python3 xxx.py 7890 my_web_frame_name:app")
        return

    print("http服務(wù)器使用的port:%s" % port)

    # 將動態(tài)路徑即存放py文件的路徑顷级,添加到path中凫乖,這樣python就能夠找到這個路徑了
    sys.path.append(g_dynamic_document_root)

    ret = re.match(r"([^:]*):(.*)", web_frame_module_app_name)
    if ret:
        # 獲取模塊名
        web_frame_module_name = ret.group(1)
        # 獲取可以調(diào)用web框架的應(yīng)用名稱
        app_name = ret.group(2)

    # 導(dǎo)入web框架的主模塊
    web_frame_module = __import__(web_frame_module_name)
    # 獲取那個可以直接調(diào)用的函數(shù)(對象)
    app = getattr(web_frame_module, app_name) 

    # print(app)  # for test

    # 啟動http服務(wù)器
    http_server = WSGIServer(port, g_static_document_root, app)
    # 運行http服務(wù)器
    http_server.run_forever()


if __name__ == "__main__":
    main()
4.打開瀏覽器效果
QQ20171101-150347@2x.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末确垫,一起剝皮案震驚了整個濱河市弓颈,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌删掀,老刑警劉巖翔冀,帶你破解...
    沈念sama閱讀 217,084評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異披泪,居然都是意外死亡纤子,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評論 3 392
  • 文/潘曉璐 我一進店門款票,熙熙樓的掌柜王于貴愁眉苦臉地迎上來控硼,“玉大人,你說我怎么就攤上這事艾少】ㄇ” “怎么了?”我有些...
    開封第一講書人閱讀 163,450評論 0 353
  • 文/不壞的土叔 我叫張陵缚够,是天一觀的道長幔妨。 經(jīng)常有香客問我鹦赎,道長,這世上最難降的妖魔是什么误堡? 我笑而不...
    開封第一講書人閱讀 58,322評論 1 293
  • 正文 為了忘掉前任古话,我火速辦了婚禮,結(jié)果婚禮上锁施,老公的妹妹穿的比我還像新娘陪踩。我一直安慰自己,他們只是感情好沾谜,可當(dāng)我...
    茶點故事閱讀 67,370評論 6 390
  • 文/花漫 我一把揭開白布膊毁。 她就那樣靜靜地躺著,像睡著了一般基跑。 火紅的嫁衣襯著肌膚如雪婚温。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,274評論 1 300
  • 那天媳否,我揣著相機與錄音栅螟,去河邊找鬼。 笑死篱竭,一個胖子當(dāng)著我的面吹牛力图,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播掺逼,決...
    沈念sama閱讀 40,126評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼吃媒,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了吕喘?” 一聲冷哼從身側(cè)響起赘那,我...
    開封第一講書人閱讀 38,980評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎氯质,沒想到半個月后募舟,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,414評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡闻察,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,599評論 3 334
  • 正文 我和宋清朗相戀三年拱礁,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片辕漂。...
    茶點故事閱讀 39,773評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡呢灶,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出钉嘹,到底是詐尸還是另有隱情鸯乃,我是刑警寧澤,帶...
    沈念sama閱讀 35,470評論 5 344
  • 正文 年R本政府宣布隧期,位于F島的核電站飒责,受9級特大地震影響赘娄,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜宏蛉,卻給世界環(huán)境...
    茶點故事閱讀 41,080評論 3 327
  • 文/蒙蒙 一遣臼、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧拾并,春花似錦揍堰、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至之碗,卻和暖如春蝙眶,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背褪那。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評論 1 269
  • 我被黑心中介騙來泰國打工幽纷, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人博敬。 一個月前我還...
    沈念sama閱讀 47,865評論 2 370
  • 正文 我出身青樓友浸,卻偏偏與公主長得像,于是被迫代替她去往敵國和親偏窝。 傳聞我的和親對象是個殘疾皇子收恢,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,689評論 2 354

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)祭往,斷路器伦意,智...
    卡卡羅2017閱讀 134,654評論 18 139
  • 原文:https://legacy.python.org/dev/peps/pep-3333 PEP:3333標(biāo)題...
    老周_o_o閱讀 2,401評論 0 5
  • 1、通過CocoaPods安裝項目名稱項目信息 AFNetworking網(wǎng)絡(luò)請求組件 FMDB本地數(shù)據(jù)庫組件 SD...
    陽明先生_X自主閱讀 15,979評論 3 119
  • 談?wù)揥EB編程的時候常說天天在寫CGI链沼,那么CGI是什么呢默赂?可能很多時候并不會去深究這些基礎(chǔ)概念沛鸵,再比如除了CGI...
    __七把刀__閱讀 2,196評論 2 11
  • 前不久的一個離婚的朋友給我說, 她的這個婚姻曲掰,其實她也是迷迷糊糊的就 結(jié)了疾捍,因為她們是家里相親安排的,剛開 始的時...
    溫柔的女生閱讀 564評論 0 1