基於Nginx location下Odoo12(僞)讀寫分離 (二)

拓撲圖

請求關係
從上圖可以看到, 其實如果Nginx不代理某些靜態文件的話, Nginx可以獨立出主服務器, 但是專業的事情還是讓專業的人來做, 各模塊static目錄下的js, css, xml 文件, /web/content/.*\.(js|css), 就還是讓Nginx來處理吧. 一些用戶上傳的附件, 還是由Odoo處理

Nginx 配置

upstream odoo-main {
    server 127.0.0.1:8469;  # 主庫
}
upstream odoo-read {
    server 127.0.0.1:8569;  # 讀從庫
}
upstream odoo-longpolling {
    server 127.0.0.1:8472;
}

server {
    listen 80;
    server_name  odoo12.jz10.com;		# 隨意配置一個域名, 自己在hosts文件裏面添加
    access_log   /var/log/nginx/odoo12/access_odoo12.log;
    error_log    /var/log/nginx/odoo12/error_odoo12.log;

    # Add Headers for odoo proxy mode
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_connect_timeout 720s;
    proxy_read_timeout 720s;
    proxy_send_timeout 720s;
	
    location /longpolling/poll {
        proxy_pass  http://odoo-longpolling;
    }

    # 只讀的請求
    location /web/dataset/search_read {
        proxy_pass  http://odoo-read;
    }
    location ~ /web/dataset/call_kw/[^/]+/(load_views|read|fields_get|name_search|name_get) {
        proxy_pass  http://odoo-read;
    }

    # 靜態文件分離
    location ~ ^/web/content/.*\.(js|css)$ {
        expires 7d;
        root /data/Odoo-12;		# 指向odoo配置文件中的 $(data_dir)
    }
    location ~ ^/[^/]+/static/.*\.(less|scss)\.css$ {
        expires 7d;
        root /data/Odoo-12/less_css;
    }
    location ~ ^/[^/]+/static/ {
        expires 7d;
        root /data/Odoo-12/addons_static;
    }
	
	# 其他Odoo請求
    location / {
        proxy_redirect  off;
        proxy_pass  http://odoo-main;
    }
    
	# common gzip
 	gzip_types text/css text/scss text/plain text/xml application/xml application/json application/javascript;
 	gzip on;
}

簡單粗暴, 分離了特定的靜態文件請求和只讀請求.

  • ^/web/content/.*\.(js|css)$ 主要是odoo將各模塊js|css文件壓縮之後產生的web.assets_bankend.js|css等, 主要是進入http://odoo12.jz10.com/web之後會請求一次
  • ^/[^/]+/static/.*\.(less|scss)\.css$ 這個是個模塊static目錄下的scss|less文件, 原本文件路徑是web/static/src/scss/banner.scss, 但是訪問的url會變成/web/static/src/scss/banner.scss.css, 這種主要是http://odoo12.jz10.com/web?debug=assets會請求這類url
  • ~ ^/[^/]+/static/ 這個就是完全代理各模塊的static目錄下的各種文件了

這些靜態文件都改爲了Nginx代理, 也就是說不需要登錄就能訪問這些文件, 但是這類靜態文件登不登陸又有什麼關係捏.

靜態文件分離

如果不想分離靜態文件, 覺得這個東西可有可無, 這一塊是可以不用參考的, 只需在Nginx配置中註釋掉靜態文件相關的location, 那樣這些文件請求自然會被odoo-main處理.
靜態文件魔改較多, 無法通過模塊的方式進行擴展, 只能改源碼了

# odoo/addons/base/models/assetsbundle.py
from odoo.tools import config	# 添加


class AssetsBundle(object):
	# ....
	def clean_attachments(self, type):
		# ---
		# 一堆代碼
		# ---
		# force bundle invalidation on other workers
        self.env['ir.qweb'].clear_caches()
        ats = ira.sudo().search(domain)	# 添加此行
		self.remove_my_att(ats)	# 添加此行
        return ats.unlink()		# 修改此行

	def remove_my_att(ats):
        for at in ats:
            path = os.path.join(config['data_dir'], at.url[1:])
            try:
                os.remove(path)
                if len(os.listdir(os.path.dirname(path))) == 0:
                    os.removedirs(os.path.dirname(path))
            except Exception as e:
                _logger.error(e)
            else:
                _logger.debug('rm file: %s', path)

    def save_attachment(self, type, content, inc=None):
        assert type in ('js', 'css')
        ira = self.env['ir.attachment']
        # -----
        # 就不復制了
        # -----
        if self.env.context.get('commit_assetsbundle') is True:
            self.env.cr.commit()

        self.clean_attachments(type)
        self.write_file(url, content.encode('utf8'))	# 添加此行
        return attachment
    
    # 添加此方法    
    def write_file(url, byte_content):
    	m_root = config['data_dir']
        if url.endswith('.less.css') or url.endswith('.scss.css'):
        	# 此類文件, 集中存放在 less_css 下
            full_path = os.path.join(m_root, 'less_css', url[1:])
        else:
        	# 其它, 其實就是 /web/content/.*\.(js|css)此類文件了
            full_path = os.path.join(m_root, url[1:])
        dn = os.path.dirname(full_path)
        if not os.path.isdir(dn):
            os.makedirs(dn)
        with open(full_path, 'wb') as fp:
            _logger.debug("create file %s on %s", url, full_path)
            fp.write(content)
	# ....

	# ....
    def preprocess_css(self, debug=False, old_attachments=None):
        #....
        if self.stylesheets:
            compiled = ""
            for atype in (SassStylesheetAsset, ScssStylesheetAsset, LessStylesheetAsset):
                assets = [asset for asset in self.stylesheets if isinstance(asset, atype)]
                #....
            while fragments:     
                # 一堆代碼
                #....
                if debug:
                    try:
                   	    #....
		                # 一堆代碼
		                #....
                        if self.env.context.get('commit_assetsbundle') is True:
                            self.env.cr.commit()
                        self.write_file(url, asset.content.encode('utf8'))	# 添加此行, 這裏就是產生scss.css文件處, 這種要重啓odoo之後, 纔會創建, 普通安裝模塊不會觸發preprocess_css
                    except psycopg2.Error:
                        pass
               

核心就是write_file, 我們在保存附件(type=js|css)的時候, 多保存了一份, 放在$(data_dir)目錄下面, 預處理scss文件的時候, 也額外存了一份. 都是按照附件的url路徑存放. 清理附件的時候, 也嘗試去$(data_dir)下面去刪除附件, 其實要是不在乎硬盤大小的話可以不去刪除.

至此, 我們解決了web/content/.*\.(js|css).scss.css文件的Nginx代理問題, 用存2份的方式, 原生無規律的存放和按照url路徑存放, 接下來就是各模塊的static目錄代理問題, 這個就是在導入模塊時, 在$(data_dir)/addons_static目錄下創建軟鏈接即可.


待更新…

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章