您好,登錄后才能下訂單哦!
一、簡介
flask中session組件可分為內置的session組件還有第三方flask-session組件,內置的session組件功能單一,而第三方的flask-sessoin可支持redis、memcached、文件等進行session的存儲。以下將介紹內置session以及第三方session組件的使用方法以及處理機制。
二、內置session處理機制
Cookie與Session
Cookie:
Cookie意為“甜餅”,是由W3C組織提出,最早由Netscape社區發展的一種機制。目前Cookie已經成為標準,所有的主流瀏覽器如IE、Netscape、Firefox、Opera等都支持Cookie。由于HTTP是一種無狀態的協議,服務器單從網絡連接上無從知道客戶身份。怎么辦呢?就給客戶端們頒發一個通行證吧,每人一個,無論誰訪問都必須攜帶自己通行證。這樣服務器就能從通行證上確認客戶身份了。這就是Cookie的工作原理。
Cookie實際上是一小段的文本信息。客戶端請求服務器,如果服務器需要記錄該用戶狀態,就使用response向客戶端瀏覽器頒發一個Cookie。客戶端瀏覽器會把Cookie保存起來。當瀏覽器再請求該網站時,瀏覽器把請求的網址連同該Cookie一同提交給服務器。服務器檢查該Cookie,以此來辨認用戶狀態。服務器還可以根據需要修改Cookie的內容
Session:
Session是另一種記錄客戶狀態的機制,不同的是Cookie保存在客戶端瀏覽器中,而Session保存在服務器上。客戶端瀏覽器訪問服務器的時候,服務器把客戶端信息以某種形式記錄在服務器上。這就是Session。客戶端瀏覽器再次訪問時只需要從該Session中查找該客戶的狀態就可以了,實質上session就是保存在服務器端的鍵值對。
如果說Cookie機制是通過檢查客戶身上的“通行證”來確定客戶身份的話,那么Session機制就是通過檢查服務器上的“客戶明細表”來確認客戶身份。Session相當于程序在服務器上建立的一份客戶檔案,客戶來訪的時候只需要查詢客戶檔案表就可以了。
第一次請求,session的創建過程
在flask上下文中介紹了,請求到flask框架會執行wsgi_app方法:
def wsgi_app(self, environ, start_response): ctx = self.request_context(environ) #實例化生成RequestContext對象 error = None try: try: ctx.push() #push上下文到LocalStack中 response = self.full_dispatch_request() #執行視圖函數過程 except Exception as e: error = e response = self.handle_exception(e) #處理異常 except: error = sys.exc_info()[1] raise return response(environ, start_response) finally: if self.should_ignore_error(error): error = None ctx.auto_pop(error) # 刪除LocalStack中的數據
在改方法中會生成一個ctx也就是RequestContext對象:
class RequestContext(object): def __init__(self, app, environ, request=None): self.app = app # app對象 if request is None: request = app.request_class(environ) self.request = request # 封裝request self.url_adapter = app.create_url_adapter(self.request) self.flashes = None self.session = None #一開始的session
在這個對象中封裝了session,最初為None。接著在wsgi_app中執行ctx.push:
def push(self): app_ctx = _app_ctx_stack.top # 獲取app上下文 if app_ctx is None or app_ctx.app != self.app: app_ctx = self.app.app_context() #將app上下文push到app_ctx對于的LocalStack中 app_ctx.push() self._implicit_app_ctx_stack.append(app_ctx) else: self._implicit_app_ctx_stack.append(None) if hasattr(sys, 'exc_clear'): sys.exc_clear() _request_ctx_stack.push(self) if self.session is None: # 判斷session是否為None,一開始為None session_interface = self.app.session_interface # 獲取操作session的對象 self.session = session_interface.open_session( #調用open_session 創建session self.app, self.request ) if self.session is None: self.session = session_interface.make_null_session(self.app)
這里我們主要關注session,前面的代碼在上下文中已經進行了相關說明,這里有個判斷session是否為None,剛開始RequestContext中的session為None,所以條件成立,此時執行以下語句:
session_interface = self.app.session_interface self.session = session_interface.open_session( self.app, self.request ) if self.session is None: self.session = session_interface.make_null_session(self.app)
首先來看session_interface = self.app.session_interface,self.app.session_interface就是app中的session_interface屬性:
session_interface = SecureCookieSessionInterface()
默認是一個SecureCookieSessionInterface()對象,該對象的內部主要實現了open_session和save_session用于使用和保存session。接著self.session被重新賦值為session_interface.open_session(self.app, self.request)方法返回的值,以下為open_session源碼:
def open_session(self, app, request): s = self.get_signing_serializer(app) #根據app.secret_key獲取簽名算法 if s is None: return None # 根據配置中的session_cookie_name獲取session對于的值 val = request.cookies.get(app.session_cookie_name) #如果request.cookies為空,val為空 if not val: return self.session_class() max_age = total_seconds(app.permanent_session_lifetime) try: data = s.loads(val, max_age=max_age) return self.session_class(data) except BadSignature: return self.session_class()
該方法返回self.session_class(),當請求第一次來時,request.cookies為None,所以val也為None,返回self.session_class(),而session_class又是SecureCookieSession:
session_class = SecureCookieSession
所以我們繼續看SecureCookieSession:
class SecureCookieSession(CallbackDict, SessionMixin): accessed = False def __init__(self, initial=None): def on_update(self): self.modified = True self.accessed = True super(SecureCookieSession, self).__init__(initial, on_update) def __getitem__(self, key): self.accessed = True return super(SecureCookieSession, self).__getitem__(key) def get(self, key, default=None): self.accessed = True return super(SecureCookieSession, self).get(key, default) def setdefault(self, key, default=None): self.accessed = True return super(SecureCookieSession, self).setdefault(key, default)
該類繼承了CallbackDict, SessionMixin我們繼續來看看CallbackDict:
class CallbackDict(UpdateDictMixin, dict): """A dict that calls a function passed every time something is changed. The function is passed the dict instance. """ def __init__(self, initial=None, on_update=None): dict.__init__(self, initial or ()) self.on_update = on_update def __repr__(self): return '<%s %s>' % ( self.__class__.__name__, dict.__repr__(self) )
也就是說SecureCookieSession繼承了CallbackDict而CallbackDict繼承了原生的dict,所以我們可以認為SecureCookieSession是一個特殊的字典,是調用了SecureCookieSessionInterface類中open_session返回的特殊字典,經過進一步分析self.session此時就是這個字典,這也意味著session在執行open_session方法時候被創建了,并保存在ctx中,也就是在RequestContext對象中,當我們使用session時候是通過全局變量session = LocalProxy(partial(_lookup_req_object, 'session'))由LocalProxy對象從ctx中獲取到session。
第二次請求
開始我們知道session第一次請求來的時候是在open_session方法之后被創建,當第二次請求時,此時在open_session方法中,val已經不在是None,此時獲取cookie的有效時長,如果cookie依然有效,通過與寫入時同樣的簽名算法將cookie中的值解密出來并寫入字典并返回,若cookie已經失效,則仍然返回'空字典',這樣以來在第二次請求中就能獲取到之前保存的session數據。
session生命周期
我們介紹了session創建時候是在ctx.push時候開始創建,也就是說在這之后我們就可以使用session,對它進行操作了,那么session什么時候保存呢?我們接下來繼續看wsgi_app:
def wsgi_app(self, environ, start_response): ctx = self.request_context(environ) error = None try: try: ctx.push() response = self.full_dispatch_request() except Exception as e: error = e response = self.handle_exception(e) except: error = sys.exc_info()[1] raise return response(environ, start_response) finally: if self.should_ignore_error(error): error = None ctx.auto_pop(error)
生成session后,接著執行self.full_dispatch_request():
def full_dispatch_request(self): """Dispatches the request and on top of that performs request pre and postprocessing as well as HTTP exception catching and error handling. .. versionadded:: 0.7 """ self.try_trigger_before_first_request_functions() #執行app.before_first_reques鉤子函數 try: request_started.send(self) # 觸發request_started信號 rv = self.preprocess_request() # 執行before_request鉤子函數 if rv is None: rv = self.dispatch_request() # 執行視圖函數 except Exception as e: rv = self.handle_user_exception(e) return self.finalize_request(rv)
這一部分先執行鉤子app.before_first_reques在觸發request_started信號,再執行before_request鉤子函數,然后在執行視圖函數,rv是執行完視圖函數的返回值,最后執行finalize_request,這里的session保存就發生在這里:
def finalize_request(self, rv, from_error_handler=False): response = self.make_response(rv) try: response = self.process_response(response) request_finished.send(self, response=response) except Exception: if not from_error_handler: raise self.logger.exception('Request finalizing failed with an ' 'error while handling an error') return response
注意這里的在最后會session判斷是否為空,會執行save_session方法,也就是SecureCookieSessionInterface的save_session方法:
def save_session(self, app, session, response): domain = self.get_cookie_domain(app) path = self.get_cookie_path(app) # If the session is modified to be empty, remove the cookie. # If the session is empty, return without setting the cookie. if not session: if session.modified: response.delete_cookie( app.session_cookie_name, domain=domain, path=path ) return # Add a "Vary: Cookie" header if the session was accessed at all. if session.accessed: response.vary.add('Cookie') if not self.should_set_cookie(app, session): return httponly = self.get_cookie_httponly(app) secure = self.get_cookie_secure(app) samesite = self.get_cookie_samesite(app) expires = self.get_expiration_time(app, session) val = self.get_signing_serializer(app).dumps(dict(session)) response.set_cookie( app.session_cookie_name, val, expires=expires, httponly=httponly, domain=domain, path=path, secure=secure, samesite=samesite )
該方法最后保存的session調用的response.set_cookie,其實是將數據保存在cookie中,也就是在客戶端的瀏覽器中,并非在服務端進行數據的保存,當請求完畢后會執行ctx.auto_pop(error)這時候會從上下文中將session和request刪除,到此,session的生命周期結束。
視圖函數使用session
在介紹flask的上下文中就已經對session進行過介紹,其本質也是通過LocalProxy操作上下文從而設置session,我們以session['username']='wd'作為列子,首先根據
session = LocalProxy(partial(_lookup_req_object, 'session'))
session是一個LocalProxy對象,執行session['username']=‘wd'則執行LocalProxy對象的__setitem__方法,而__setitem__方法中則是調用_get_current_object獲取ctx中的session對象,而其對象本質是一個特殊的字典,相當于在字典中加一對key,value。
小結
flask內置session本質上依靠上下文,當請求到來時,調用session_interface中的open_session方法解密獲取session的字典,并保存在RequestContext.session中,也就是上下文中,然后在視圖函數執行完畢后調用session_interface的save_session方法,將session以加密的方式寫入response的cookie中,瀏覽器再保存數據。而第三方的session組件原理就是基于是open_session方法和save方法,從而實現session更多的session保存方案。
三、第三方組件flask-session
flask-session支持多種數據庫session保存方案如:redis、memchached、mongodb甚至文件系統等。官方文檔: https://pythonhosted.org/Flask-Session/
安裝:
pip3 install flask-session
redis
import redis from flask import Flask, session from flask_session import Session from datetime import timedelta app = Flask(__name__) app.debug = True app.secret_key = 'adavafa' app.config['SESSION_TYPE'] = 'redis' # session類型為redis app.config['SESSION_PERMANENT'] = True # 如果設置為True,則關閉瀏覽器session就失效。 app.config['PERMANENT_SESSION_LIFETIME']=timedelta(seconds=20) #一個持久化的會話的生存時間,是一個datetime.timedelta對象,也可以用一個整數來表示秒,前提設置了PERMANENT_SESSION_LIFETIME為True app.config['SESSION_USE_SIGNER'] = False # 是否對發送到瀏覽器上session的cookie值進行加密,默認False app.config['SESSION_KEY_PREFIX'] = 'flask-session' # 保存到redis中的key的前綴 app.config['SESSION_COOKIE_NAME']= 'session_id' # 保存在瀏覽器的cookie名稱 app.config['SESSION_REDIS'] = redis.Redis(host='10.1.210.33', port=‘6379',password=‘123123') # 用于連接redis的配置 #其他配置,不經常使用 app.config['SESSION_COOKIE_DOMAIN']='127.0.0.1' # 設置cookie的域名,不建議設置默認為server_name app.config['SESSION_COOKIE_PATH']='/' # 會話cookie的路徑。 如果未設置,則cookie將對所有url有效,默認為'/' app.config['SESSION_COOKIE_HTTPONLY']=True # 是否啟動httponly,默認為true,為了防止xss腳本訪問cookie Session(app) @app.route('/login') def index(): session["username"]="jack" return 'login' if __name__ == '__main__': app.run()
Memchached
import memcache from flask import Flask, session from flask_session import Session from datetime import timedelta app = Flask(__name__) app.debug = True app.secret_key = 'adavafa' app.config['SESSION_TYPE'] = ‘memcached' # session類型為memcached app.config['SESSION_PERMANENT'] = True # 如果設置為True,則關閉瀏覽器session就失效。 app.config['PERMANENT_SESSION_LIFETIME']=timedelta(seconds=20) #一個持久化的會話的生存時間,是一個datetime.timedelta對象,也可以用一個整數來表示秒,前提設置了PERMANENT_SESSION_LIFETIME為True app.config['SESSION_USE_SIGNER'] = False # 是否對發送到瀏覽器上session的cookie值進行加密,默認False app.config['SESSION_KEY_PREFIX'] = 'flask-session' # 保存到緩存中的key的前綴 app.config['SESSION_COOKIE_NAME']= 'session_id' # 保存在瀏覽器的cookie名稱 app.config['SESSION_MEMCACHED'] = memcache.Client(['10.1.210.33:12000']) #連接 #其他配置,不經常使用 app.config['SESSION_COOKIE_DOMAIN']='127.0.0.1' # 設置cookie的域名,不建議設置默認為server_name app.config['SESSION_COOKIE_PATH']='/' # 會話cookie的路徑。 如果未設置,則cookie將對所有url有效,默認為'/' app.config['SESSION_COOKIE_HTTPONLY']=True # 是否啟動httponly,默認為true,為了防止xss腳本訪問cookie Session(app) @app.route('/login') def index(): session["username"]="jack" return 'login' if __name__ == '__main__': app.run()
Filesystem
from flask import Flask, session from flask_session import Session from datetime import timedelta app = Flask(__name__) app.debug = True app.secret_key = 'adavafa' app.config['SESSION_TYPE'] = 'filesystem' # session類型為filesystem app.config['SESSION_FILE_DIR']='/opt/db' #文件保存目錄 app.config['SESSION_FILE_THRESHOLD'] = 300 # 存儲session的個數如果大于這個值時,開始刪除 app.config['SESSION_PERMANENT'] = True # 如果設置為True,則關閉瀏覽器session就失效。 app.config['PERMANENT_SESSION_LIFETIME']=timedelta(seconds=20) #一個持久化的會話的生存時間,是一個datetime.timedelta對象,也可以用一個整數來表示秒,前提設置了PERMANENT_SESSION_LIFETIME為True app.config['SESSION_USE_SIGNER'] = False # 是否對發送到瀏覽器上session的cookie值進行加密,默認False app.config['SESSION_KEY_PREFIX'] = 'flask-session' # 保存到文件中的key的前綴 app.config['SESSION_COOKIE_NAME']= 'session_id' # 保存在瀏覽器的cookie名稱 #其他配置,不經常使用 app.config['SESSION_COOKIE_DOMAIN']='127.0.0.1' # 設置cookie的域名,不建議設置默認為server_name app.config['SESSION_COOKIE_PATH']='/' # 會話cookie的路徑。 如果未設置,則cookie將對所有url有效,默認為'/' app.config['SESSION_COOKIE_HTTPONLY']=True # 是否啟動httponly,默認為true,為了防止xss腳本訪問cookie Session(app) @app.route('/login') def index(): session["username"]="jack" return 'login' if __name__ == '__main__': app.run()
mongodb
import pymongo from flask import Flask, session from flask_session import Session from datetime import timedelta app = Flask(__name__) app.debug = True app.secret_key = 'adavafa' app.config['SESSION_TYPE'] = 'mongodb' # session類型為mongodb app.config['SESSION_MONGODB'] = pymongo.MongoClient('localhost',27017) app.config['SESSION_MONGODB_DB'] = '數據庫名稱' app.config['SESSION_MONGODB_COLLECT'] = '表名稱' app.config['SESSION_PERMANENT'] = True # 如果設置為True,則關閉瀏覽器session就失效。 app.config['PERMANENT_SESSION_LIFETIME']=timedelta(seconds=20) #一個持久化的會話的生存時間,是一個datetime.timedelta對象,也可以用一個整數來表示秒,前提設置了PERMANENT_SESSION_LIFETIME為True app.config['SESSION_USE_SIGNER'] = False # 是否對發送到瀏覽器上session的cookie值進行加密,默認False app.config['SESSION_KEY_PREFIX'] = 'flask-session' # 保存的session的key的前綴 app.config['SESSION_COOKIE_NAME']= 'session_id' # 保存在瀏覽器的cookie名稱 #其他配置,不經常使用 app.config['SESSION_COOKIE_DOMAIN']='127.0.0.1' # 設置cookie的域名,不建議設置默認為server_name app.config['SESSION_COOKIE_PATH']='/' # 會話cookie的路徑。 如果未設置,則cookie將對所有url有效,默認為'/' app.config['SESSION_COOKIE_HTTPONLY']=True # 是否啟動httponly,默認為true,為了防止xss腳本訪問cookie Session(app) @app.route('/login') def index(): session["username"]="jack" return 'login' if __name__ == '__main__': app.run()
sqlalchemy
import redis from flask import Flask, session from flask_session import Session from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) app.debug = True app.secret_key = 'adavafa' # 設置數據庫鏈接 app.config['SQLALCHEMY_DATABASE_URI'] = 'mysql+pymysql://root:dev@127.0.0.1:3306/devops?charset=utf8' app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = True # 實例化SQLAlchemy db = SQLAlchemy(app) app.config['SESSION_TYPE'] = 'sqlalchemy' # session類型為sqlalchemy app.config['SESSION_SQLALCHEMY'] = db # SQLAlchemy對象 app.config['SESSION_SQLALCHEMY_TABLE'] = '表名' # session要保存的表名稱 app.config['SESSION_PERMANENT'] = True # 如果設置為True,則關閉瀏覽器session就失效。 app.config['PERMANENT_SESSION_LIFETIME']=timedelta(seconds=20) #一個持久化的會話的生存時間,是一個datetime.timedelta對象,也可以用一個整數來表示秒,前提設置了PERMANENT_SESSION_LIFETIME為True app.config['SESSION_USE_SIGNER'] = False # 是否對發送到瀏覽器上session的cookie值進行加密,默認False app.config['SESSION_KEY_PREFIX'] = 'flask-session' # 保存的session的key的前綴 app.config['SESSION_COOKIE_NAME']= 'session_id' # 保存在瀏覽器的cookie名稱 #其他配置,不經常使用 app.config['SESSION_COOKIE_DOMAIN']='127.0.0.1' # 設置cookie的域名,不建議設置默認為server_name app.config['SESSION_COOKIE_PATH']='/' # 會話cookie的路徑。 如果未設置,則cookie將對所有url有效,默認為'/' app.config['SESSION_COOKIE_HTTPONLY']=True # 是否啟動httponly,默認為true,為了防止xss腳本訪問cookie Session(app) @app.route('/login') def index(): session["username"]="jack" return 'login' if __name__ == '__main__': app.run() ###使用SQLAlchemy時候先確保數據庫和表都存在 在命令行中創建表 #>>> from app import db #>>> db.create_all()
原理
這里以redis作為session存儲方案做分析,以下是RedisSessionInterface源碼:
class RedisSessionInterface(SessionInterface): serializer = pickle session_class = RedisSession def __init__(self, redis, key_prefix, use_signer=False, permanent=True): if redis is None: from redis import Redis redis = Redis() self.redis = redis self.key_prefix = key_prefix self.use_signer = use_signer self.permanent = permanent def open_session(self, app, request): sid = request.cookies.get(app.session_cookie_name) if not sid: sid = self._generate_sid() return self.session_class(sid=sid, permanent=self.permanent) if self.use_signer: signer = self._get_signer(app) if signer is None: return None try: sid_as_bytes = signer.unsign(sid) sid = sid_as_bytes.decode() except BadSignature: sid = self._generate_sid() return self.session_class(sid=sid, permanent=self.permanent) if not PY2 and not isinstance(sid, text_type): sid = sid.decode('utf-8', 'strict') val = self.redis.get(self.key_prefix + sid) if val is not None: try: data = self.serializer.loads(val) return self.session_class(data, sid=sid) except: return self.session_class(sid=sid, permanent=self.permanent) return self.session_class(sid=sid, permanent=self.permanent) def save_session(self, app, session, response): domain = self.get_cookie_domain(app) path = self.get_cookie_path(app) if not session: if session.modified: self.redis.delete(self.key_prefix + session.sid) response.delete_cookie(app.session_cookie_name, domain=domain, path=path) return httponly = self.get_cookie_httponly(app) secure = self.get_cookie_secure(app) expires = self.get_expiration_time(app, session) val = self.serializer.dumps(dict(session)) self.redis.setex(name=self.key_prefix + session.sid, value=val, time=total_seconds(app.permanent_session_lifetime)) if self.use_signer: session_id = self._get_signer(app).sign(want_bytes(session.sid)) else: session_id = session.sid response.set_cookie(app.session_cookie_name, session_id, expires=expires, httponly=httponly, domain=domain, path=path, secure=secure)
分析:RedisSessionInterface繼承了SessionInterface
class SessionInterface(FlaskSessionInterface): def _generate_sid(self): return str(uuid4()) def _get_signer(self, app): if not app.secret_key: return None return Signer(app.secret_key, salt='flask-session', key_derivation='hmac')
而SessionInterface又繼承了FlaskSessionInterface,而FlaskSessionInterface又繼承了flask內置的SessionInterface,并且RedisSessionInterface重寫了內置session的open_session和save_session.
首先是RedisSessionInterface實例化用于初始化配置,例如redis的連接、簽名配置、過期配置、前綴配置等。
接下來看兩個核心方法:open_session方法和save_session方法。
open_session:
def open_session(self, app, request): sid = request.cookies.get(app.session_cookie_name) #獲取session id if not sid: #判斷session id是否為空,為空表示第一次請求 sid = self._generate_sid() # 返回使用uuid4隨機字符串 return self.session_class(sid=sid, permanent=self.permanent) if self.use_signer:# 判斷簽名配置 signer = self._get_signer(app) if signer is None: return None try: sid_as_bytes = signer.unsign(sid) # 對session id 進行加密簽名 sid = sid_as_bytes.decode() except BadSignature: sid = self._generate_sid() return self.session_class(sid=sid, permanent=self.permanent) if not PY2 and not isinstance(sid, text_type): sid = sid.decode('utf-8', 'strict') val = self.redis.get(self.key_prefix + sid) # 獲取seession數據 if val is not None: try: data = self.serializer.loads(val) # 反序列化數據 return self.session_class(data, sid=sid) #返回 except: return self.session_class(sid=sid, permanent=self.permanent) return self.session_class(sid=sid, permanent=self.permanent)
改方法先從cookie中獲取session id,然后對session id判斷是否為空,為空表示第一次請求,則通過self._generate_sid()返回隨機字符串,作為返回給瀏覽器的sessionid
def _generate_sid(self): return str(uuid4())
接著判斷簽名判斷是否為true,然后對session 進行簽名,這里和內置session不同的是獲取session的時候通過self.redis.get(self.key_prefix + sid)在redis中進行獲取。
save_session:
def save_session(self, app, session, response): domain = self.get_cookie_domain(app) # 獲取cookie中的域名 path = self.get_cookie_path(app) # 獲取cookie 中path if not session: # 判斷有誤session對象 if session.modified: #沒有但是被修改了,表示已經被刪除了 self.redis.delete(self.key_prefix + session.sid) #清空session response.delete_cookie(app.session_cookie_name, domain=domain, path=path) return httponly = self.get_cookie_httponly(app) secure = self.get_cookie_secure(app) expires = self.get_expiration_time(app, session) val = self.serializer.dumps(dict(session)) self.redis.setex(name=self.key_prefix + session.sid, value=val, time=total_seconds(app.permanent_session_lifetime)) #保存session if self.use_signer: session_id = self._get_signer(app).sign(want_bytes(session.sid)) else: session_id = session.sid response.set_cookie(app.session_cookie_name, session_id, # 設置cookie expires=expires, httponly=httponly, domain=domain, path=path, secure=secure)
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。