nginx 結合python bottle 實驗限制靜態(tài)文件的訪問

背景:

在部分的業(yè)務過程中拉鹃,我們服務器上的部分靜態(tài)資源文件是需要對應權限才可以進行訪問擎值。所以我們在使用nginx提供web服務的時候慌烧,需要限制部分的靜態(tài)資源文件只允許內部進行訪問,內部判斷相關訪問文件的權限之后再進行相關文件服務的提供鸠儿。

實踐:

1.首先搭建一個測試使用的靜態(tài)文件放置root /data/app/html/:


image.png
<html>
<head>
<title>protect</title>

<head>
</body>

<h1>protect</h1>
<div style="width:500px; height: 500px; border: 1px solid #ccc;">
    <img style="width:500px; height: 500px; border: 1px solid #ccc;" src='../upload/0.jpeg'>
       
</div>


<img src='/static/001.txt'>

<img src='/static/s.png'>

</body>
</html>

2.新增nginx的web.conf虛擬主機文件:

server {
    listen 80;
    server_name 192.168.182.155;
    root /data/app/html/; #靜態(tài)文件項目的目錄
        
    location / {
        
        index  Index.html index.html;
        #proxy_pass http://192.168.182.155:8089;
    }
    
    location ~* ^/(upload)/{
        #proxy_pass http://www.baidu.com;
        #
        #internal;
        #sendfile on;
        #tcp_nopush on;
        #add_header 'Access-Control-Allow-Origin' '*';
        #add_header 'Access-Control-Allow-Credentials' 'true';
        #add_header  'Cache-Control no-cache' 'no-store';
        #proxy_pass http://192.168.182.155:8089;
        #rewrite ^/ http://192.168.182.155:8089;
        #proxy_set_header Host $host;
        #proxy_set_header X-Real-IP $remote_addr;
        #proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        #alias /data/app/html2/static/$1; #當請求”/upload/0.jpeg”將返回”/data/app/html2/static/0.jpeg”
        
        #internal;
        #proxy_redirect off;
        #proxy_set_header Host  $host;
        #proxy_set_header X-Real-IP $remote_addr;
        #proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        #proxy_pass http://192.168.182.155:8089;
        
    internal; # 限制內部訪問的關鍵字段
        alias /data/app/html2/static/$1;    //文件可以放到別的目錄
        
    }
}

3.重啟啟動 nginx -s reload

4.查詢頁面訪問的情況: curl 192.168.182.155

5.當訪問: 192.168.182.155/upload/XXXXXX的時候會匹配到 location ~* ^/(upload)/

6.準備相關的bottle服務/data/app/xianzhi/app.py:

#!/usr/bin/evn python
# coding=utf-8

# 導入程序需要的日志包模塊
import logging
import sys
from functools import wraps
from beaker.middleware import SessionMiddleware
from bottle import route, run, TEMPLATE_PATH, default_app, static_file, get, error, request, redirect, template, response, HTTPResponse
import os

# 導入自定義的路由視圖模塊杏死,即URL路徑


# 獲取本腳本所在的路徑
pro_path = os.path.split(os.path.realpath(__file__))[0]
sys.path.append(pro_path)

# 定義static路徑,即靜態(tài)資源路徑捆交,如css,js,及樣式中用到的圖片等
static_path = os.path.join(pro_path, 'static')
# 定義模板路徑
TEMPLATE_PATH.append(os.path.join(pro_path, 'template'))

# 創(chuàng)建日志目錄
if not os.path.exists('log'):
    os.mkdir('log')
# 定義日志目錄
log_path = ('/'.join((pro_path, 'log')))

# 定義日志輸出格式
logging.basicConfig(level=logging.ERROR,
                    format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
                    datefmt='%Y-%m-%d %H:%M:%S',
                    filename="%s/error_log" % log_path,
                    filemode='a')

# 設置session參數(shù)
session_opts = {
    'session.type': 'file',
    'session.cookei_expires': 3600,
    'session.data_dir': '/tmp/sessions',
    'sessioni.auto': True
}


def login_required(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        session = request.environ.get('beaker.session')  # 獲取session
        if not session.get('login'):
            return '還沒登入J缫怼!品追!'
        return f(*args, **kwargs)

    return decorated_function


@error(404)
def error404(error):
    """定制錯誤頁面"""
    return '404'


@get('/favicon.ico')
def favicon():
    pass


@route('/')
def index():
    return 'index'


@get('/user/')
def user():
    # return  'sdasda'
    return template('upload')


# @route('/static/<filepath:path>')
# def server_static(filepath):
#     """設置靜態(tài)內容路由"""
#
#     print('靜態(tài)路由:', static_path)
#     return static_file(filepath, root=static_path)


# [root@bogon ~]# curl -I http://192.168.182.155/upload/0.jpeg


# @get('/upload/<filepath:path>')
# # @login_required
# def upload(filepath):
#     # response['Content-Disposition: attachment; filename='] = 'asjjshdha'
#     response.headers['X-asdas'] = 'asasaaa'
#     response.headers['X-Accel-Redirect'] = '/upload/%s' % filepath
#     response.headers['Content-Disposition'] = 'attachment; filename=asasas'
#     print('/upload/%s' % filepath)
#     print('靜態(tài)路由1:', static_path)
#     print('靜態(tài)路由2:', '/data/app/xianzhi'+'/upload/%s' % filepath)
#     return static_file(filepath, root='/data/app/xianzhi/upload/')


# @get('/upload/<filepath:path>')
# # @login_required
# def upload(filepath):
#     # response['Content-Disposition: attachment; filename='] = 'asjjshdha'
#     # response.headers['X-asdas'] = 'asasaaa'
#     response.headers['X-Accel-Redirect'] = '/data/app/xianzhi'+'/upload/%s' % filepath
#     response.headers['Content-Disposition'] = 'attachment; filename=asasas'
#     print('/upload/%s' % filepath)
#     print('靜態(tài)路由1:', static_path)
#     print('靜態(tài)路由2:', '/data/app/xianzhi'+'/upload/%s' % filepath)
#     return static_file(filepath, root='/data/app/xianzhi/upload/')


# # 這個方法是可行的Pā!肉瓦!
# @route('/upload/<filename:re:.*\.jpeg>')
# def send_image(filename):
#     # response.set_header('Content-Language', 'en')
#     # response.set_header('X-Accel-Redirect',  '/upload/%s' % filename)
#     response.set_header('X-Sendfile', '/upload/%s' % filename)
#     response.set_header('Content-Type', 'application/jpeg')
#     response.set_header('X-Accel-Redirect', '/upload/%s'% filename)
#     fsize = os.path.getsize('/data/app/xianzhi' + '/upload/%s' % filename)
#     # response.set_header('Content-Disposition', 'attachment; filename=' + '/upload/%s' % filename)
#     # print('文件大小:', fsize)
#     response.set_header('Content-Length', fsize)  #
#     # response.set_header('Content-Disposition', "attachment; filename=\"" + filename + "\";")
#     print('成功了嗎T饩胃惜!-----------------!')
#     return response


# return static_file(filename, root='/data/app/xianzhi/upload/', mimetype='image/jpeg')


# 這個方法是可行的D牡瘛4场!
@route('/upload/<filename:re:.*\.rar>')
def send_image(filename):
    # response.set_header('Content-Language', 'en')
    response.set_header('X-Accel-Redirect',  '/upload/%s' % filename)
    response.set_header('X-Sendfile', '/upload/%s' % filename)
    # response.set_header('Content-Type', 'application/octet-stream')
    response.set_header('Content-Disposition', 'attachment;')
    print('成功了嗎rarK购俊@妗!')
    # return  response
    # return static_file(filename, root='/data/app/xianzhi/upload/', mimetype='image/jpeg')


@route('/upload/<filename:re:.*\.jpeg>')
def send_image(filename):
    # response.set_header('Content-Language', 'en')
    # response.set_header('X-Accel-Redirect', '/upload/%s' % filename)
    # response.set_header('X-Sendfile','/upload/%s' % filename)
    # response.set_header('Content-Type', 'application/octet-stream')
    # response.set_header('Content-Disposition', 'attachment;')
    print('成功了嗎222221てА?繁埂!')
    return response
    # return static_file(filename, root='/data/app/xianzhi/upload/', mimetype='image/jpeg')


# @get('/upload/<filepath:path>')
# # @login_required
# def upload(filepath):
#     # response['Content-Disposition: attachment; filename='] = 'asjjshdha'
#     # response.headers['X-asdas'] = 'asasaaa'
#
#     fsize = os.path.getsize('/data/app/xianzhi' + '/upload/%s' % filepath)
#     print('文件大小:', fsize)
#     response.headers['Content-Length'] = fsize
#     response.headers['Content-Disposition'] = 'attachment; filename=/upload/' + filepath
#     response.headers['Content-Type'] = 'application/octet-stream'
#     response.headers['X-Accel-Redirect'] = '/upload/%s' % filepath
#     response.headers['X-Sendfile'] = '/upload/%s' % filepath
#     print('/upload/%s' % filepath)
#     print('靜態(tài)路由1:', static_path)
#     print('靜態(tài)路由2:', '/data/app/xianzhi' + '/upload/%s' % filepath)
#     # return
#     # return HTTPResponse(body, **headers)
#     # return response
#     return static_file(filepath, root='/data/app/xianzhi/upload/')


# header('Content-Disposition: attachment; filename="(希望客戶下載到的文件名)"');
# @get('/upload/<filepath:path>')
# @login_required
# def upload(filepath):
#     print(filepath)
#     response['Content-Type'] = 'application/jpg'
#     response['X-Accel-Redirect'] = '/vagrant/upload/%s' % filepath
#
#     print(response)
#     return response

@route('/login')
def login():
    # session['login'] = True
    s = request.environ.get('beaker.session')  # 如果帳號密碼正確钉疫,則獲取環(huán)境變量中的beaker.session對象硼讽,并賦值給s,然后我們就可以用字典的方式牲阁,往s里面添加一些我們要存進去的數(shù)據(jù)固阁,如帳號名,帳號id城菊,權限等等
    s['login'] = True
    s.save()
    s = request.environ.get('beaker.session')  # 獲取session
    login = s.get('login', None)  # 從session中獲取Key為user的值备燃,是上面登陸的時候保存進來
    print(login)
    return 'log in'


@route('/logout')
def logout():
    # session['login'] = False
    s = request.environ.get('beaker.session')  # 如果帳號密碼正確,則獲取環(huán)境變量中的beaker.session對象役电,并賦值給s,然后我們就可以用字典的方式棉胀,往s里面添加一些我們要存進去的數(shù)據(jù)法瑟,如帳號名,帳號id唁奢,權限等等
    s['login'] = False
    s.save()
    return 'log out'


# 函數(shù)主入口
if __name__ == '__main__':
    app_argv = SessionMiddleware(default_app(), session_opts)
    run(app=app_argv, host='127.0.0.1', port=8888, debug=True, reloader=True)
else:
    application = SessionMiddleware(default_app(), session_opts)


# 直接的啟動程序
# run(host='localhost', port=8080, reloader=True, debug=True)

# if __name__ == '__main__':
#     app = default_app()
#     app = SessionMiddleware(app, session_opts)
#     run(app=app, host='127.0.0.1', port=8080, debug=True, server='gevent')
# else:
#     application = SessionMiddleware(default_app(), session_opts)
#
# # # 函數(shù)主入口
# # if __name__ == '__main__':
# #     run(host='127.0.0.1', port=8090, debug=True, reloader=True)
# # else:
# #     pass

7:使用 uwsgi 啟動app.py,對應的配置文件app_uwsgi.ini:

image.png
[uwsgi]
socket = 127.0.0.1:8086
chdir = /data/app/xianzhi/
wsgi-file = /data/app/xianzhi/app.py
limit-as = 512
reload-on-as = 256
reload-on-rss = 192
processes = 2
max-requests = 2000
pythonpath = /data/app/xianzhi/
log-maxsize = 10000000
madisable-logging = true
master = true
vacuum = true
no-orphans = true

7:使用 uwsgi 啟動app.py 方式:


image.png
# cd /data/app/xianzhi
# uwsgi app_uwsgi.ini 

因為使用了uwsgi啟動霎挟,需要使用sockie的方式進行處理請求:

8:配置web_app.conf,用戶通過nginx 訪問 uwsgi開啟的服務

server {
   listen 8089;
   server_name 192.168.182.155;
   root /data/app/xianzhi/;
       
   location / {
       include uwsgi_params;
       uwsgi_param UWSGI_PYHOME /data/app/xianzhi;
       uwsgi_param UWSGI_CHDIR /data/app/xianzhi;
       uwsgi_param UWSGI_SCRIPT app; # 對應main.py
       uwsgi_pass  127.0.0.1:8086;
       client_max_body_size       50m;
       proxy_connect_timeout      1; #nginx跟后端服務器連接超時時間(代理連接超時)
       proxy_send_timeout         120; #后端服務器數(shù)據(jù)回傳時間(代理發(fā)送超時)
       proxy_read_timeout         120; #連接成功后麻掸,后端服務器響應時間(代理接收超時)
   }
}

8: 配置靜態(tài)頁面的訪問路徑酥夭,通過代理指向到192.168.182.155:8089


image.png

9:啟動瀏覽器刷192.168.182.155 觀察是否訪問到了后端服務接口

補充說明:

圖示說明:bottle 提供的static_file也提供了對應X-Sendfile的方式進行靜態(tài)文件的處理
再非緩存情況206狀態(tài)的情況下,他直接的顯示調用了


Sendfile方式處理靜態(tài)文件
image.png
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末脊奋,一起剝皮案震驚了整個濱河市熬北,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌诚隙,老刑警劉巖讶隐,帶你破解...
    沈念sama閱讀 218,122評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異久又,居然都是意外死亡巫延,警方通過查閱死者的電腦和手機效五,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來炉峰,“玉大人畏妖,你說我怎么就攤上這事√劾” “怎么了戒劫?”我有些...
    開封第一講書人閱讀 164,491評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長竿开。 經常有香客問我谱仪,道長,這世上最難降的妖魔是什么否彩? 我笑而不...
    開封第一講書人閱讀 58,636評論 1 293
  • 正文 為了忘掉前任疯攒,我火速辦了婚禮,結果婚禮上列荔,老公的妹妹穿的比我還像新娘敬尺。我一直安慰自己,他們只是感情好贴浙,可當我...
    茶點故事閱讀 67,676評論 6 392
  • 文/花漫 我一把揭開白布砂吞。 她就那樣靜靜地躺著,像睡著了一般崎溃。 火紅的嫁衣襯著肌膚如雪蜻直。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,541評論 1 305
  • 那天袁串,我揣著相機與錄音概而,去河邊找鬼。 笑死囱修,一個胖子當著我的面吹牛赎瑰,可吹牛的內容都是我干的。 我是一名探鬼主播破镰,決...
    沈念sama閱讀 40,292評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼餐曼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了鲜漩?” 一聲冷哼從身側響起源譬,我...
    開封第一講書人閱讀 39,211評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎孕似,沒想到半個月后瓶佳,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 45,655評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡鳞青,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,846評論 3 336
  • 正文 我和宋清朗相戀三年霸饲,在試婚紗的時候發(fā)現(xiàn)自己被綠了为朋。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,965評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡厚脉,死狀恐怖习寸,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情傻工,我是刑警寧澤霞溪,帶...
    沈念sama閱讀 35,684評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站中捆,受9級特大地震影響鸯匹,放射性物質發(fā)生泄漏。R本人自食惡果不足惜泄伪,卻給世界環(huán)境...
    茶點故事閱讀 41,295評論 3 329
  • 文/蒙蒙 一殴蓬、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蟋滴,春花似錦染厅、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至尔苦,卻和暖如春涩馆,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背允坚。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評論 1 269
  • 我被黑心中介騙來泰國打工魂那, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人屋讶。 一個月前我還...
    沈念sama閱讀 48,126評論 3 370
  • 正文 我出身青樓冰寻,卻偏偏與公主長得像须教,于是被迫代替她去往敵國和親皿渗。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,914評論 2 355