Python實(shí)現(xiàn)接口下載json文件并指定文件名稱
文件下載與亂碼問題
在 Web 應(yīng)用中,文件下載通常通過設(shè)置 HTTP 響應(yīng)頭中的Content-Disposition來實(shí)現(xiàn)。這個(gè)響應(yīng)頭告訴瀏覽器這是一個(gè)文件下載,而不是普通的頁面內(nèi)容。然而,如果文件名包含非 ASCII 字符,比如中文、日文或阿拉伯文等,直接設(shè)置文件名可能會導(dǎo)致亂碼問題。這是因?yàn)?HTTP 頭默認(rèn)使用 ASCII 編碼,對于非 ASCII 字符,需要進(jìn)行適當(dāng)?shù)木幋a處理。
使用 Python 處理文件下載
在 Python 中,我們可以使用urllib.parse.quote函數(shù)來對文件名進(jìn)行編碼,這樣可以確保文件名在 HTTP 頭中正確傳輸。此外,為了支持多種瀏覽器,我們還可以設(shè)置filename*參數(shù),使用 RFC 5987 標(biāo)準(zhǔn)來指定文件名的編碼。
以下是一個(gè)示例代碼,展示了如何使用 Python 生成一個(gè)帶有自定義文件名的 JSON 文件下載響應(yīng):
import json import urllib.parse from flask import Response def export_data_as_json(result): # 假設(shè)result是一個(gè)包含數(shù)據(jù)的字典 data_ = result['data'] orig_name = data_['orig_name'] # 將數(shù)據(jù)轉(zhuǎn)換為JSON格式的字符串 json_data = json.dumps(data_) # 對原始文件名進(jìn)行URL編碼,避免URL注入攻擊 safe_filename = urllib.parse.quote(orig_name + ".json") # 設(shè)置HTTP響應(yīng)頭,指定文件名和編碼 headers = { "Content-Disposition": f'attachment; filename="{safe_filename}"; filename*=UTF-8\'{safe_filename}' } # 創(chuàng)建HTTP響應(yīng)對象 return Response( content=json_data, media_type="application/json", headers=headers )
分析代碼實(shí)現(xiàn)
在上述代碼中,我們首先從result字典中提取出需要導(dǎo)出的數(shù)據(jù),并獲取原始文件名。然后,我們使用json.dumps將數(shù)據(jù)轉(zhuǎn)換為 JSON 格式的字符串。
接下來,我們使用urllib.parse.quote函數(shù)對原始文件名進(jìn)行 URL 編碼。這一步是必要的,因?yàn)樗梢苑乐?URL 注入攻擊,并且確保文件名中的特殊字符被正確處理。
在設(shè)置 HTTP 響應(yīng)頭時(shí),我們使用了Content-Disposition頭,并設(shè)置了attachment和filename參數(shù)。filename參數(shù)指定了文件的默認(rèn)名稱,而filename*參數(shù)則使用了 RFC 5987 標(biāo)準(zhǔn)來指定文件名的編碼。這樣,即使文件名包含非 ASCII 字符,瀏覽器也能正確解析和顯示。
最后,我們創(chuàng)建了一個(gè)Response對象,并設(shè)置了內(nèi)容、媒體類型和頭部信息,然后返回這個(gè)響應(yīng)對象。當(dāng)這個(gè)響應(yīng)被發(fā)送到客戶端時(shí),瀏覽器會提示用戶下載文件,并且文件名會顯示為用戶自定義的名稱,不會出現(xiàn)亂碼。
為什么這種方法有效
這種方法有效,因?yàn)樗裱?HTTP 和 Web 瀏覽器處理文件下載的標(biāo)準(zhǔn)。通過使用filename*
參數(shù),我們告訴瀏覽器文件名的編碼方式,這樣瀏覽器就能正確解碼并顯示文件名。同時(shí),使用urllib.parse.quote
函數(shù)確保了文件名的安全性和兼容性。
拓展:Python如何獲取JSON數(shù)據(jù)的指定標(biāo)簽內(nèi)容
很多人會用到JSON格式的數(shù)據(jù),但是如果想取得JSON數(shù)據(jù)中的某個(gè)鍵內(nèi)容,就必須要一層層往下套取才能拿到,如果層次非常多的話,套取將會非常的麻煩。
比如隨意編寫的JSON內(nèi)容,想取得相應(yīng)的值會非常麻煩,在獲取請求的數(shù)據(jù)時(shí),數(shù)組內(nèi)容的數(shù)據(jù)可能會不同,無法準(zhǔn)確定位到底是哪個(gè)目錄,如果后期目錄修改了,我們也需要重新修改操作目錄,將會變得非常麻煩。
{ "errcode":0, "errmsg":"ok", "info":{ "sp_no":"202203030015", "sp_name":"風(fēng)險(xiǎn)", "sp_status":3, "template_id":"tetefdfdfdfefsfdfssa", "apply_time":1614759, "applyer":{ "userid":"3940", "partyid":"2" }, "sp_record":[ { "sp_status":3, "approverattr":1, "details":[ { "approver":{ "userid":"3940" }, "speech":"", "sp_status":3, "sptime":1614756, "media_id":[ ] } ] }, { "sp_status":1, "approverattr":1, "details":[ { "approver":{ "userid":"5" }, "speech":"", "sp_status":1, "sptime":0, "media_id":[ ] } ] } ], "notifyer":[ ], "apply_data":{ "contents":[ { "control":"Table", "id":"Table-1614750144354", "title":[ { "text":"測試", "lang":"zh_CN" } ], "value":{ "tips":[ ], "members":[ ], "departments":[ ], "files":[ ], "children":[ { "list":[ { "control":"Date", "id":"Date-1614750", "title":[ { "text":"日期", "lang":"zh_CN" } ], "value":{ "tips":[ ], "members":[ ], "departments":[ ], "date":{ "type":"day", "s_timestamp":"1600000000000" }, "files":[ ], "children":[ ], "stat_field":[ ], "sum_field":[ ], "related_approval":[ ], "students":[ ], "classes":[ ], "docs":[ ], "wedrive_files":[ ] } }, { "control":"Text", "id":"Text-1614", "title":[ { "text":"測試2", "lang":"zh_CN" } ], "value":{ "text":"abcd", "tips":[ ], "members":[ ], "departments":[ ], "files":[ ], "children":[ ], "stat_field":[ ], "sum_field":[ ], "related_approval":[ ], "students":[ ], "classes":[ ], "docs":[ ], "wedrive_files":[ ] } }, { "control":"Textarea", "id":"Textarea-1614", "title":[ { "text":"描述", "lang":"zh_CN" } ], "value":{ "text":"點(diǎn)點(diǎn)滴滴", "tips":[ ], "members":[ ], "departments":[ ], "files":[ ], "children":[ ], "stat_field":[ ], "sum_field":[ ], "related_approval":[ ], "students":[ ], "classes":[ ], "docs":[ ], "wedrive_files":[ ] } }, { "control":"File", "id":"File-16147", "title":[ { "text":"關(guān)聯(lián)附件", "lang":"zh_CN" } ], "value":{ "tips":[ ], "members":[ ], "departments":[ ], "files":[ { "file_id":"fdfdfdafdfdfdsfdassfdfadfaafafasffasfasffsdafsfsffasfsdfas" } ], "children":[ ], "stat_field":[ ], "sum_field":[ ], "related_approval":[ ], "students":[ ], "classes":[ ], "docs":[ ], "wedrive_files":[ ] } }, { "control":"RelatedApproval", "id":"Relatal-161", "title":[ { "text":"關(guān)聯(lián)", "lang":"zh_CN" } ], "value":{ "tips":[ ], "members":[ ], "departments":[ ], "files":[ ], "children":[ ], "stat_field":[ ], "sum_field":[ ], "related_approval":[ { "template_names":[ { "text":"測試", "lang":"zh_CN" } ], "sp_status":1, "name":"張三", "create_time":1611713200, "sp_no":"202201260001" } ], "students":[ ], "classes":[ ], "docs":[ ], "wedrive_files":[ ] } } ] } ], "stat_field":[ ], "sum_field":[ ], "related_approval":[ ], "students":[ ], "classes":[ ], "docs":[ ], "wedrive_files":[ ] } } ] }, "comments":[ { "commentUserInfo":{ "userid":"3940" }, "commenttime":16147, "commentcontent":"是,請xxx ", "commentid":"69358", "media_id":[ ] } ] } }
正常情況下,我們是通過Test['info']['apply_data']['contents'][0]['value']['children'][0]['list'][3]['title'][0]['text']抓取數(shù)據(jù),如果抓取數(shù)據(jù)不存在,則直接報(bào)錯(cuò),當(dāng)然,我們可以使用get方式去抓取,如果沒有直接返回空,這樣其實(shí)意義不大,所以我后面寫了這個(gè)代碼,可以隨意獲取相關(guān)JSON數(shù)據(jù)的健對應(yīng)的值。
它可以直接返回你需要獲取的健對應(yīng)的層級目錄,不需要專門去編寫相關(guān)目錄,就能通過該目錄獲取相關(guān)層級的其他目錄
比如,我想獲取JSON數(shù)據(jù)中,指定key為:text,值為:關(guān)聯(lián)的附件,然后就能獲取當(dāng)前層級下的節(jié)點(diǎn)內(nèi)容了,其中”['title'][0]['text']“是排除,如果使用則排除這些節(jié)點(diǎn),不使用則返回完整的JSON目錄。
dict1 = get_json_to_dict(detail, 'text', '關(guān)聯(lián)附件', len("['title'][0]['text']"))
通過上面的函數(shù)就能獲取到這個(gè)JSON目錄"['info']['apply_data']['contents'][0]['value']['children'][0]['list'][3]['title'][0]['text']",如果加了排除,則直接返回這個(gè)目錄['info']['apply_data']['contents'][0]['value']['children'][0]['list'][3],最終調(diào)用處返回這個(gè)目錄對應(yīng)的JSON對象內(nèi)容,非常方便的解決了我們自己寫目錄的煩惱,也不怕目錄改動,因?yàn)樗茏詣诱业阶约盒枰逆I值的相關(guān)目錄了
有了這個(gè)字典,我就能獲取指定字典的相關(guān)值,而我編寫的這個(gè)方法,也能獲取相關(guān)健值,如獲取相關(guān)的all_file_id,整體只需要使用兩個(gè)方法就能解決問題。
如下是具體的代碼片段:
loc = locals() # 獲取本地資源 def get_var_name(var): """ 通過變量進(jìn)行獲取當(dāng)前變量的名稱 """ for k, v in loc.items(): if loc[k] is var: return k # 后面是具體編寫的JSON獲取代碼 get_key_list = [] # 共用的循環(huán)列表 def get_json_key_value(json_object, key_name, key_value): """ 獲取相關(guān)JSON數(shù)據(jù)的鍵值進(jìn)行對比,并返回相關(guān)的節(jié)點(diǎn)內(nèi)容 """ if isinstance(json_object, dict): # 字典 for x in range(len(json_object)): key_tmp = list(json_object.keys())[x] value_tmp = json_object[key_tmp] if len(key_value) == 0: if key_name == key_tmp: get_key_list.append(value_tmp) else: if key_name == key_tmp and key_value == value_tmp: return "['" + key_tmp + "']" result = get_json_key_value(value_tmp, key_name, key_value) # 遞歸調(diào)用 if len(key_value) != 0 and result: return "['" + key_tmp + "']" + result elif isinstance(json_object, list): # 列表 ind = -1 for k in json_object: ind += 1 if isinstance(k, dict): for x in range(len(k)): key_tmp = list(k.keys())[x] value_tmp = k[key_tmp] if len(key_value) == 0: if key_name == key_tmp: get_key_list.append(value_tmp) else: if key_name == key_tmp and key_value == value_tmp: return "[" + str(ind) + "]" + "['" + key_tmp + "']" result = get_json_key_value(value_tmp, key_name, key_value) # 遞歸調(diào)用 if len(key_value) != 0 and result: return "[" + str(ind) + "]" + "['" + key_tmp + "']" + result key_list_tmp = get_key_list.copy() return key_list_tmp def get_json_content(json_obj, key_var, value_var): """ 包裝相關(guān)JSON返回節(jié)點(diǎn)內(nèi)容,通過鍵值進(jìn)行對比,并返回相關(guān)的節(jié)點(diǎn)內(nèi)容,如果未找到則返回空 """ key_value = get_json_key_value(json_obj, key_var, value_var) if key_value: return key_value else: return "" def get_json_to_dict(json_obj, key_var, value_var, jump_num): """ 通過鍵值內(nèi)容,獲取JSON數(shù)據(jù)對象的相關(guān)字典內(nèi)容,并返回對應(yīng)的JSON數(shù)據(jù)對象,可以通過排除方式進(jìn)行鎖定層級對象 """ content = get_json_content(json_obj, key_var, value_var) if content: if jump_num: content = content[0:len(content)-int(jump_num)] try: result = eval(get_var_name(json_obj) + content) except: result = "" else: return "" return result
具體使用代碼測試
if __name__ == '__main__': get_key_list = [] # 執(zhí)行之前清空一下公共數(shù)組 dict1 = get_json_to_dict(detail, 'text', '關(guān)聯(lián)附件', len("['title'][0]['text']")) # 獲取指定字典內(nèi)容 all_file_id = get_json_key_value(dict1, "file_id", "") # 獲取指定字典中相關(guān)的數(shù)據(jù)健值 print(all_file_id)
到此這篇關(guān)于Python實(shí)現(xiàn)接口下載json文件并指定文件名稱的文章就介紹到這了,更多相關(guān)Python下載json并指定文件名稱內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用pygame實(shí)現(xiàn)垃圾分類小游戲功能(已獲校級二等獎(jiǎng))
這篇文章主要介紹了使用pygame實(shí)現(xiàn)垃圾分類小游戲功能(已獲校級二等獎(jiǎng)),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-07-07Python實(shí)現(xiàn)的維尼吉亞密碼算法示例
這篇文章主要介紹了Python實(shí)現(xiàn)的維尼吉亞密碼算法,結(jié)合實(shí)例形式分析了基于Python實(shí)現(xiàn)維尼吉亞密碼算法的定義與使用相關(guān)操作技巧,需要的朋友可以參考下2018-04-04Python3爬蟲發(fā)送請求的知識點(diǎn)實(shí)例
在本篇文章里小編給大家分享的是一篇關(guān)于Python3爬蟲發(fā)送請求的知識點(diǎn)實(shí)例,需要的朋友們可以學(xué)習(xí)下。2020-07-07Django上使用數(shù)據(jù)可視化利器Bokeh解析
這篇文章主要介紹了Django上使用數(shù)據(jù)可視化利器Bokeh解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-07-07Python 實(shí)現(xiàn)的 Google 批量翻譯功能
這篇文章主要介紹了Python 實(shí)現(xiàn)的 Google 批量翻譯功能,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-08-08Python實(shí)現(xiàn)把utf-8格式的文件轉(zhuǎn)換成gbk格式的文件
這篇文章主要介紹了Python實(shí)現(xiàn)把utf-8格式的文件轉(zhuǎn)換成gbk格式的文件,本文給出了實(shí)現(xiàn)代碼并同時(shí)剖析了代碼的作用,需要的朋友可以參考下2015-01-01