背景:
在部分的業(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