標籤: 網頁設計

  • 除了思域,這3款10來萬的轎車也能讓你爽到停不下來

    除了思域,這3款10來萬的轎車也能讓你爽到停不下來

    但速度上去之後還是很有感覺的,特別是當你跑高速時,沉穩的底盤精準的轉向能給予你足夠的信心,可能不經意間你的時速就上百了,如果你覺得普通版的高爾夫不夠過癮,那就上GTI或R-Line吧,畢竟小鋼炮是不會浪得虛名的。說到這可能很多朋友糊塗了,操控都是它們的主旋律,那到底要選哪款呀。

    最近不少網友諮詢想要一輛具有駕駛樂趣的緊湊型轎車該買哪款好,小雅腦中第一個冒出來的當然是思域啦,但是仔細想想思域太火了、等車實在太煎熬,所以今天我推薦另外三款,快來看看有沒有對你口味的:

    一、外觀與內飾

    如果你說思域是日繫緊湊型轎車的顏值擔當,馬自達車主可要表示不服了,瞧瞧這輛昂克賽拉,我保證在車流中你能一眼就找出來,魂動設計賦予了它獨特的韻律美,盾型進氣格柵、翼型鍍鉻飾條、犀利的前大燈、偏長的引擎蓋、再加上動感的線條,說不驚艷那還真是騙人的。

    第二個要介紹的是福克斯,它有着一張略顯囂張的前臉,獠牙狀進氣格柵顯露出十足的攻擊性,鷹眼大燈看上去炯炯有神,車身線條力量感十足,果然很有運動氣息。

    相比之下,小雅覺得高爾夫看起來要低調很多,沒有昂克賽拉那嫵媚多姿的車身線條,也沒有福克斯那搶眼的馬丁臉,可偏偏是這樣的大眾家族式設計風格依舊能討得不少人的喜愛,畢竟每個人的審美不一樣。

    我們接着來看內飾:

    昂克賽拉與福克斯的用料都中規中矩,不過昂克賽拉的中控面板上按鍵比較少,看起來十分簡潔,並且懸浮式的中控显示屏提升不少檔次感。福克斯的中控台佔用空間較多,讓我覺得有點壓迫感,並且做工要粗糙一些。

    高爾夫的內飾設計是三車中最有質感的,雖然看起來並沒什麼新鮮味道,但它摸起來軟、做工細緻,而且中控面板的設計整體偏向駕駛席一側,方便駕駛員在行車時進行操作。

    二、駕駛感受

    關於造型設計就先說到這了,畢竟我們今天的主題是駕駛樂趣 ,那麼三者中誰的駕控最好呢?

    昂克賽拉最大的優點主要有兩個,首先自然吸氣發動機動力輸出很線性,變速箱降擋平順,還有一點是轉向特別靈敏。雖然小雅覺得人車合一這個口號略顯誇張,但不可否認它開起來確實很靈活輕快。

    對了,補充一點,昂克賽拉還加上了GVC扭矩分配系統,用於改善過彎時車輛的動態表現,集這麼多亮點於一身,我想這也是廣大車迷朋友們喜歡它的主要原因。

    再來看看福克斯,這位運動健將近年來慢慢朝舒適性方向有所靠攏了。以前的福克斯動力很猛,還可謂是指哪打哪,但現在略偏舒適的調校讓它變得不那麼純粹了。

    但它依舊是這個級別裏面不可忽視的,它的1.5T發動機功率在同排量渦輪增壓發動機中最出色的,最大馬力高達181匹,儘管油耗有點讓人心疼,但是它加速暢快啊。總的來說儘管整體質量口碑一般,但這並不影響年輕人將其作為人生第一部車的首選。

    很多高爾夫車主被稱為“神車黨”,不過你要知道高爾夫有很多種,分為普通版、R-Line、GTI,動力的選擇也是多種多樣,其中的1.4T發動機匹配7擋雙離合變速箱可以說是黃金組合了,變速箱換擋快,動力的話初段加速不會太給力,需要你踩深一點油門。

    但速度上去之後還是很有感覺的,特別是當你跑高速時,沉穩的底盤精準的轉向能給予你足夠的信心,可能不經意間你的時速就上百了,如果你覺得普通版的高爾夫不夠過癮,那就上GTI或R-Line吧,畢竟小鋼炮是不會浪得虛名的。

    說到這可能很多朋友糊塗了,操控都是它們的主旋律,那到底要選哪款呀!別急,我們接着來看它們的配置:

    三、裝備率

    1、福克斯全系標配前後排頭部氣囊/氣簾,氣囊的重要性想必大家也都知道,所以說福克斯這點做的很厚道,而高爾夫要在指導價為14.49萬的2018款 1.6L 自動舒適型上才開始配備,昂克賽拉就更讓小雅失望了,只有頂配車型才配備有。

    2、福克斯與昂克賽拉的頂配車型帶有主動安全系統,高爾夫全系沒有這一配置,而是多出疲勞駕駛提示功能,但小雅覺得有點華而不實。

    3、再來看看倒車視頻影像,福克斯又給我了驚喜,做到了全系標配,昂克賽拉要在指導價為12.89萬的2017款 三廂 1.5L 手動豪華型才開始配備,而2018款的高爾夫只有GTI與280TSI 自動旗艦型上才帶有。

    4、在燈光配置方面,昂克賽拉的LED大燈普及率高,在12.89萬的2017款 三廂 1.5L 手動豪華型上便可獲得,高爾夫要在15.79萬的2018款 280TSI 手動R-Line型才能買到,福克斯則全系都找不到LED大燈的影子。

    5、另外,昂克賽拉全系標配多功能方向盤,福克斯全系標配8英寸中控屏,高爾夫全系支持全車車窗一鍵升降。

    小雅覺得三車中福克斯的價格不算高,但配置的普及率卻非常高,再結合上面的表現來看是三車中性價比最高的。

    四、結語

    當然車無完車,三者最大的不足是空間都不太理想,畢竟這不是它們主攻的方面,另外高爾夫的價格比較高,特別是售價高達20多萬的GTI令不少人望而卻步。

    但不管怎樣,手握住它們三中間任何一輛的方向盤,你都會忍不住多跑一會,難道不是嗎?本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※為什麼 USB CONNECTOR 是電子產業重要的元件?

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    ※台北網頁設計公司全省服務真心推薦

    ※想知道最厲害的網頁設計公司"嚨底家"!

    ※推薦評價好的iphone維修中心

  • 男人最愛的這項熱血汽車運動,真的很爽!

    男人最愛的這項熱血汽車運動,真的很爽!

    除了可以感受到賽車的熱烈氣氛以外,還可以近距離看到不同賽車的結構和技術亮點。當然了,還可以去了解一下賽車手究竟都是怎樣的人,究竟真的是“超人么”。這次的視頻,我們還特別找到了珠海高卡車隊的老闆兼車手王遠先生,去了解一下賽車究竟是怎麼一回事如。

    對於喜歡汽車的朋友來說,總會看過一點關於賽車的東西。不過對於大部分對汽車不太熟悉的朋友,賽車貌似離我們非常遙遠,簡直好像是另外一個星球的事情。而賽車往往也是很高深莫測的精密机械,有超凡的性能,連駕駛賽車的車手也好像需要類似飛行員的體質和能力,才能駕馭這種可怕的機器!

    真的是這樣么?

    為了探尋這個秘密,我們到了珠海國際賽車場ZIC,去觀看泛珠三角賽車節春季賽(簡稱泛珠春季賽)。泛珠春季賽基本集合了大部分常見的賽車類別,包括方程式、prototype、GT、TCR、漂移賽車和改裝房車等等。除了可以感受到賽車的熱烈氣氛以外,還可以近距離看到不同賽車的結構和技術亮點。當然了,還可以去了解一下賽車手究竟都是怎樣的人,究竟真的是“超人么”。

    這次的視頻,我們還特別找到了珠海高卡車隊的老闆兼車手王遠先生,去了解一下賽車究竟是怎麼一回事如。如果想體驗賽車,又有什麼門檻。當然了,我們也對他們車隊一台GK5賽車進行剖析,看看它究竟和我們一般街道行駛的飛度又有什麼相同和不同的地方。

    如果你對賽車好奇,又想了解一下賽車究竟是怎麼回事,或者已經是一個熱血賽車迷的話,就不要錯過本期的視頻了。

    本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

    ※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

    南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

    ※教你寫出一流的銷售文案?

    ※超省錢租車方案

  • 買毛線飛度捷達!9萬就有高顏值省油SUV了!

    買毛線飛度捷達!9萬就有高顏值省油SUV了!

    雖然是定位年輕,但內飾除了配色之外就看不出有多個性,中規中矩就像大眾,哦,還是比大眾要靈活一些。斑馬系統還是很棒棒的,和目前那些什麼“天貓精靈”有異曲同工之妙,一句話能夠解決的問題,很多人可能還是習慣按鍵。

    10萬買什麼車?飛度啊!還用問?

    這樣的問答非常“知乎”。

    然而,這種“知乎”風格的回答只適合一部分人,你看,飛度一個月也就賣幾千台。其實10萬可以買的車很多,如果你想買“飛度”那樣省油大空間的,也有不少選擇,譬如今天我們視頻的主角,榮威RX3。

    RX3採用家族的“律動”設計,雖然談不上多驚艷,但目前這套設計在榮威RX5、i6上表現良好,市場接受度高,就像是大眾的風格那樣,為人們廣泛接受。

    雖然是定位年輕,但內飾除了配色之外就看不出有多個性,中規中矩就像大眾,哦,還是比大眾要靈活一些。

    斑馬系統還是很棒棒的,和目前那些什麼“天貓精靈”有異曲同工之妙,一句話能夠解決的問題,很多人可能還是習慣按鍵。

    1.6L阿特金森循環發動機主打燃油經濟性,配合上來自愛信的CVT變速箱,整體表現能夠滿足日常的使用,發動機輸出線性,符合這個排量發動機的表現。

    加減速測試

    至於駕駛感受方面,這台車挺日系的,怎麼說呢,一方面,懸挂偏軟,動力偏線性;另一方面,追求低油耗,不盲目追求性能。

    總結

    榮威RX3作為一款新生代車型,無論是外觀設計還是內飾做工都做到了這個級別的前列,並且1.6L+CVT的動力組合更加適合城市中穿梭,如果你的駕駛習慣是溫和的,沒有太多的動力需求,僅僅作為代步的話,榮威RX3值得你留意。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

    ※Google地圖已可更新顯示潭子電動車充電站設置地點!!

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※別再煩惱如何寫文案,掌握八大原則!

    網頁設計最專業,超強功能平台可客製化

  • 50年不怎麼變,它卻始終是王者

    50年不怎麼變,它卻始終是王者

    2011年,廣州車展上新一代的911車型正式發布。新一代保時捷911車內多處添加鍍鉻裝飾,檔次再度升級。新一代保時捷911 Carrera搭載的是3。4L水平對置發動機,最大功率達到345馬力,911 Carrera S搭載一台3。8L水平對置發動機,最大功率達到400馬力,而911 Turbo最大功率達到542馬力,此外,保時捷為新一代911全系標配了7速保時捷雙離合變速箱。

    說起跑車,我相信這款有着將近50年不變的後置后驅結構和萌萌噠”青蛙眼睛”的跑車,一定讓每位車迷都魂牽夢繞,從它誕生至今,因為其獨特的風格和超強的耐用性而享譽世界,沒錯,它就是世界經典—保時捷911。

    但是它成為一代經典的傳奇生涯你是否了解呢?不知道也沒關係,今天就為你再現它的成名之路以及競技生涯。

    自誕生日起,保時捷至今歷經七代車型,911於1963年以跑車的身份亮相法蘭克福車展。“蛙眼大燈”的前臉設計、COUpE車身造型、後置六缸水平對置發動機、良好的操控性為保時捷911的成功奠定了基礎。在不斷的升級換代中,911又加入了很多的創新系元素,但新一代的911整體設計思路都會傳承911車型的經典元素,所以911每一款成功的車型都會有屬於自己的氣質,它所體現出來的“車魂”是唯一的。

    第一代誕生於1963年,它的出現奠定了日後整個911系列車型的幾個重要元素,”蛙眼大燈“、後置六缸水平對置發動機以及空氣冷卻系統。底盤技術多沿用356的技術,包括四輪碟式制動器和后懸挂,前懸挂則為全新開發的。

    第二代是911車系裡面時間最長的一代,歷時15年。在這期間,911Turbo等技術不斷創新的全新車型為911贏得了許多國際大獎,其中四輪驅動的959曾是1984和1986年的達喀爾拉力賽的冠軍。

    第三代911開始,在引擎變速箱方面進行了技術革新,之後又相繼推出了新開發的四輪驅動911Carrera4 、Carrera以及第二代911Turbo車型,其中Carrera採用了當時比較新穎的“Tiptronic”自動變速器。另外由第三代開始,底盤編號開始正式記錄入911的車型歷史中。

    到了第四代911,Targa獨成一派,作為911新的版本車型。1992年,為了舉辦Carrera杯比賽,911 Carrera再度推出其賽道版本RS,該車擁有300匹的馬力,最高時速269KM/h。四代後期全球推出新的廢氣排放標準,為此911放棄了風冷發動機繼而推出新款水冷發動機,此款水冷發動機也是第五代911車型996的引擎雛形。

    第五代911正式開始採用水冷發動機,1999年保時捷穩定管理系統首次搭載在新問世的Carrera 4車型上,在五代時還發生件非常有趣的事,在勒芒大賽中獲獎的911GT1因為規則前進氣口必須修改,於是966式的新車誕生了,正式命名為911 GT1 Evolution。

    第六代911車身外觀依然是以流暢簡潔為主,經典的圓形大燈,鬼臉大燈下增加了兩個小燈,911也相繼推出敞篷型和四驅車型。第六代保時捷911(997)除了缸內直噴、主動懸挂系統和7速保時捷雙離合變速箱外,911 Turbo又增加了可變幾何渦輪和膨脹進氣歧管等技術。

    2011年,廣州車展上新一代的911車型正式發布。新一代保時捷911車內多處添加鍍鉻裝飾,檔次再度升級。新一代保時捷911 Carrera搭載的是3.4L水平對置發動機,最大功率達到345馬力,911 Carrera S搭載一台3.8L水平對置發動機,最大功率達到400馬力,而911 Turbo最大功率達到542馬力,此外,保時捷為新一代911全系標配了7速保時捷雙離合變速箱。

    911系列分為為Carrera系列、 Targa系列、Turbo系列、Turbo S系列、GT系列。

    其中的Carrera系列作為911車系當中的主打產品,款式是最多的,它也是整個911車系的靈魂。

    Targa的整體風格造型都顯得獨具特色、精美絕倫。這款極富典雅氣息的911跑車有自己的一套美學標準,透明的車頂從擋風玻璃一直延伸到引擎艙蓋,這樣設計讓車內的環境更親近大自然,寬大的天窗展開面積可達到0.45平方米,並且能夠在尾門的下方平穩滑行。

    911Turbo系列是整個系列中歷史最悠久的,可以追溯到1974年,適逢經濟衰退和石油缺乏的時期,於是這款名為911Turbo以”追求高效率“的新概念跑車就孕育而生。這也是保時捷的首款搭載渦輪增壓的911車型。

    TurboS 系列是Turbo的強化版本,在性能上有了實質性的突破,最大的輸出功率是390KW,比Turbo系列搞出了22KW,峰值扭矩更是達到了700牛.米,這是在民用版的車型中動力最為強勁的民用版車型。

    保時捷GT系列因為是為賽道而打造的車型,所以在性能配置和底盤調校上都更有賽道的風格。911GT系列的運動感比其他系列的會更強,不管是GT2、GT3還是GT3 RS都匹配了6MT的變速箱,操控性會更好,而且在車身的輕量化方面也做得很好,同時在韌性碰撞及安全性上有更大的提升。

    結語:911之所以是經典,離不開其經典的設計元素,也離不開它出色的性能表現以及對自身不斷完善,追求新技術的理念;當然了,更離不開它極其出色的可靠性以及實用性。曾經有個名人說:保時捷既可以穿梭於非洲沙漠甚至是沙漠,又可以開着它去廣場閑庭散步,穿梭於擁堵的城市街道看盡都市繁華。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

    南投搬家公司費用需注意的眉眉角角,別等搬了再說!

    ※教你寫出一流的銷售文案?

  • 合資轎車/自主SUV?15萬預算就該這麼選!

    合資轎車/自主SUV?15萬預算就該這麼選!

    配置這東西買的時候看不出來,用着沒有才坑爹。最近剛試駕一款合資小型SUV,頂配車型都沒有主駕駛化妝鏡。嘖······15萬落地,合資品牌優惠完基本上也只能要個次低配車型,就當為品牌和机械性能買單,哦,還有一點很重要,主流合資品牌的二手保值率還是不錯的,配置。

    當你每天都在看各種類型的“XX萬該買什麼車”,這都快成為一種套路化的流程。當你結合實際市場來看,這個價格又會顯得有些尷尬,理由沒別的——“落地價”三個字足矣,稅費保險先不算,基於中國特色的4S店購車流程,購車預算離最終成交價總會有些差距。在15萬這個大多數消費者的購車價位段中,你會發現自己要遇上無數個“艱難的選擇”。

    就從實際市場出發,如果指導價15萬內的產品,如果4S店報出七折以下且不含附加條件,那隻能說你和這家店老總關係硬到“老鐵送個飛機”的地步,有一點大家都清楚,4S店現在掙錢的主要渠道早就不是賣車了。目前市場韓系車不景氣,之前陪朋友去看K3,1.6L自動擋最低配指導價10.68萬,綜合優惠2.5萬,車價優惠1.2萬,要滿足另外那1.3萬的條件繁瑣的頭皮發麻。

    網上的新車落地攻略一抓一大把,都說的很簡單。建議各位去嘗試一下和4S店談談“裸車開走”這件事的複雜程度,至少筆者買車的時候,銷售明確表示:不在店內上牌+保險=不賣。想要裸車有想要優惠,現有4S銷售體系下很難實現。豪華車可能好一些,畢竟指導價底子夠厚。

    思域1.5T自動擋最低配,不算商業保險落地都不止15萬

    實際上裸車能優惠兩萬,對15萬級產品來說,稅費就算送的了,但這個級別能直接優惠兩萬的真的不多,大家看的基本是“綜合優惠”,而這個綜合優惠,一般是沒有那麼好拿的。

    回到正題,15萬購車的選擇很多嗎?真不多。如果要合資品牌,“緊湊級轎車+小型SUV”可以說完了,還得是中配以下。要是本田/馬自達這樣的個性之選,15萬還挺懸。自主品牌對15萬這個級別到做的挺好的,配置全/顏值高,就是太多人過不了自己心中“可靠性”那個坎。

    合資品牌的配置低已經不是談資是行規,都說經濟型車是拿來開的,但真正接受“買發動機送車”的用戶又有多少呢?配置這東西買的時候看不出來,用着沒有才坑爹。最近剛試駕一款合資小型SUV,頂配車型都沒有主駕駛化妝鏡。嘖······

    15萬落地,合資品牌優惠完基本上也只能要個次低配車型,就當為品牌和机械性能買單,哦,還有一點很重要,主流合資品牌的二手保值率還是不錯的,配置?汽配城走起吧。

    15萬落地選合資,管開不要想別的;那自主呢?可以提要求的地方就很多啦。很簡單的一點:自主品牌上升集中在SUV,合資15萬撐死來個小型,自主大把緊湊級可選,尺寸即正義,同時自主品牌在設計上的進步顯而易見。

    經常在一篇導購文章的評論區看到“中國人要買中國車”的觀點,相信現在說這句話不用像早幾年那樣咬牙切齒了,時下自主品牌中並不缺乏明星車型,在一些方面已經達到了與合資品牌五五開的水平,同時在向更好的方面發展,也許再過幾年,我們對自主品牌的印象不僅是停留在“配置高,價格低”上。

    做過一些市場調查,實際很多普通消費者對汽車產品的認識並不算高,選車基本延續“品牌-顏值-價格”依次步進,這也是自主品牌在第一輪就出局的原因。15萬內自主品牌有很大的產品空間,但大多數人不知道,知道的可能會有顧慮。很多人只認為自主的“大一級”僅體現在配置上的花架子,自主還需要更多時間為自己正名。

    這並不是一篇導購,15萬落地確實是一個尷尬的選擇,它不像20萬落地能夠有“雞頭鳳尾”之選,合資老實上低配,要麼選擇自主。如果沒有品牌忠誠度還好說,如果是想:“我要買本田,我要地球夢,我要創馳藍天”,那除掉發動機以外,其它的東西也就不要多講究了。

    買車就像堆積木,就算你是大神,想要堆個別墅也要積木夠多,而15萬內的產品卻只給你一個搭房頂的量,那你最終是就要個房頂還是來個雜物間?花15萬購車就像一個做減法的過程,性能-外觀-內飾-價格-品牌。它們就是一個大天平,很難做到“兩頭冒尖”。車企一樣是在做減法,只是合資的那個減號是大寫加粗,自主則做了模糊處理。對消費者來說,車企只會讓你知道它想讓你知道的。

    可以這麼說:“購買價值+使用體驗+使用時長”組成了一款車的伴隨你的全周期,最終它們都會走向零點。但選擇時的側重決定了你具體要哪款產品。買車尷尬的不是選擇怎樣的產品,而是沒有搞懂自己的需求,也可以為大家提供一個萬金油的解決方案:遇事不決上豐田!本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    ※想知道最厲害的網頁設計公司"嚨底家"!

    ※別再煩惱如何寫文案,掌握八大原則!

    ※產品缺大量曝光嗎?你需要的是一流包裝設計!

  • 【實拍】能賣得過凱美瑞邁騰?20萬級最熱門中型車到了!

    【實拍】能賣得過凱美瑞邁騰?20萬級最熱門中型車到了!

    而車尾造型簡潔,還帶有小鴨尾式的隆起。比較讓人費解的是它那雙C字型尾燈,雖然個性,但放在一款大尺寸的B級車身上顯得小氣,與簡潔明了的頭燈也沒太大呼應。內裝部分,它的設計沒有我們想象中那麼動感,造型四平八穩,反倒是具有幾分商務氣息。

    近日,虎哥收到一則重磅消息,那就是在廣州地區的一家廣汽本田4S店已經有全新一代雅閣到店!聽到這一則消息的虎哥馬上放開手中的糯米雞,帶上小夥伴飛奔到這家廣汽本田4S店!

    視頻看完還沒過癮?咱們繼續往下看。

    其實雅閣對於國內朋友來說是一款相當熟悉的車型,而對於廣東地區的朋友來說,它更加是屬於具有特殊情懷的車型!早在1999年3月份,第6代雅閣就正式在廣州實現國產,作為廣汽本田成立后推出的第一款車型它被寄予厚望。

    而截止到2002年第6代車型停產,它銷量一直很火爆,耐用、駕駛舒適成為它的最大標籤!在1999年-2002年間它銷量累計達到了13.8萬

    輛!

    緊接着推出的7代雅閣也一度造成一車難求的現象,也是經過兩代車型的努力,雅閣車型在家用中型車市場確立了標杆地位。

    而8代雅閣以前衛、富有動感的外觀,實用的大空間亦獲得優秀的市場表現。

    然而,從9代雅閣開始,“鍍鉻狂魔式”的前臉造型,和略顯臃腫的車身線條讓雅閣車型的油膩指數直線飆升!也是在這一代開始人們更多的認為它其實是一輛大叔座駕。

    當然,廣汽本田也意識到這代車型設計有些用力過猛,所以在後來改款的9.5代設計向運動感回歸,銷量得以上升!

    時至今日,第10代雅閣也即將來到我們身邊,“油膩”這個標籤也徹底與它脫離了關係!而關於它的具體細節我們就來細細分析。

    10代雅閣的前臉營造出強烈的視覺衝擊力,看實車的時候這種感覺尤為明顯。中網上粗壯的一條鍍鉻飾條立體感強,而頭燈內部一字排開的LED燈組,十分不低調!

    (注:本文圖片拍攝場地為廣汽本田第一店)

    而設計師為側面造型畫下了濃墨重彩的一筆,Coupe式的車身設計,具有溜背式的車尾造型,車頂弧線平滑。而A柱的位置比上一代車型延後了100mm,發動機艙更修長、造型也被壓得更低,運動感已相當明顯。

    輪轂的造型比較動感,但從目前的信息來看,雅閣的1.5T頂配車型也只配備17英寸的輪圈,它放在10代雅閣身上只是顯得剛剛夠用。想營造出讓人熱血噴張的運動感,它遠遠不行。或者廠家是出於對減低油耗的考慮,才限制了輪圈規格。畢竟它採用的是米其林primacy 3st浩悅系列 225/50 R17 規格的輪胎,它是一款注重降低油耗同時具備一定的操控性的輪胎型號。

    尾部帶有真雙出排氣,這點是比較厚道的。而車尾造型簡潔,還帶有小鴨尾式的隆起。比較讓人費解的是它那雙C字型尾燈,雖然個性,但放在一款大尺寸的B級車身上顯得小氣,與簡潔明了的頭燈也沒太大呼應。

    內裝部分,它的設計沒有我們想象中那麼動感,造型四平八穩,反倒是具有幾分商務氣息。

    而新車型的內飾在細節處理方面有了較明顯進步。它加入了深色的木紋飾板和金屬拉絲材質進行點綴,比以前採用的鋼琴烤漆更顯檔次感。而且做工水準也更符合B級車定位。

    儀錶盤左側設置了液晶显示屏,它能显示的多種信息,實用性不錯。值得一提的是,中控台上獨立式的8英寸多媒體觸控屏操作流暢,系統反應很快,而且显示界面也簡潔而細膩!比上一代車型好用不少,而兩側設置有實體按鍵,在開車過程中盲操作也便利,這提高了駕駛安全性。

    而中控屏支撐Honda CONNECT功能,這是一套本田開發的智能互聯繫統。頂配車型帶有前排座椅通風、加熱功能,雙區自動空調還帶有空氣凈化功能,而詳細的配置信息會在後期公布。

    這個內飾,並不能給人驚艷感,但它實用性很不錯,我想用一個“功能產生美”來形容它最貼切!

    本田的乘坐空間最大化理念在新車型上依然有很好的體現,它溜背式的尾部設計沒有對後排頭部空間帶來過多影響。而對於身高177cm的虎哥來說,它營造出接近3拳的腿部空間,翹個二郎腿很合適。

    而座椅柔軟程度和日產天籟有得一拼,坐墊長度也足夠,對於大腿的承托到位,中央扶手的長度和高度也到位,舒適性高!

    只是稍有遺憾的是後排乘客能享受到的配置基本上只有後排出風口和中央扶手上帶有的兩個杯架。

    關於新車預定:

    銷售人員表示,第10代雅閣現在已經接受預定,喜歡它的朋友可以多加留意,因為車型還沒上市,所以提車時間現在還不能確定。

    來到4S店看全新雅閣的人真的很多,可見它對於消費者吸引力還是比較大,而與這些潛在客戶交談時,他們也表示新車型內飾實用性強、做工有了進步!

    寫在最後:第10代雅閣即將到來,它的造型無疑有了脫胎換骨般的變化,其造型確實富有運動感、衝擊力!而內飾的質感得到進步,但是整體水準仍然只屬於B級車應該有的水平,乘坐空間表現出色,座椅很舒適!1.5T+CVT的動力總成雖值得期待,但2.0T+10AT車型的缺失確實有些遺憾,不過作為主力銷售的1.5T車型到底具備多大的競爭力,那就要等待後期它的配置和價格信息公布!

    特別鳴謝以下經銷商提供拍攝車輛:廣汽本田第一店;

    電話:020-36312608;地址:廣東省廣州市白雲區黃石東路448號。本站聲明:網站內容來源於http://www.auto6s.com/,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※別再煩惱如何寫文案,掌握八大原則!

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    ※超省錢租車方案

    ※教你寫出一流的銷售文案?

    網頁設計最專業,超強功能平台可客製化

    ※產品缺大量曝光嗎?你需要的是一流包裝設計!

  • 這 10 行比較字符串相等的代碼給我整懵逼了,不信你也來看看

    這 10 行比較字符串相等的代碼給我整懵逼了,不信你也來看看

    抱歉用這種標題吸引你點進來了,不過你不妨看完,看看能否讓你有所收穫。​(有收穫,請評論區留個言,沒收穫,下周末我直播吃**,哈哈,這你也信)

    補充說明:微信公眾號改版,對各個號主影響還挺大的。目前從後台數據來看,對我影響不大,因為我這反正都是小號,閱讀量本身就少的可憐,真相了,狗頭(剛從交流群學會的表情)。

    先直接上代碼:

    boolean safeEqual(String a, String b) {
       if (a.length() != b.length()) {
           return false;
       }
       int equal = 0;
       for (int i = 0; i < a.length(); i++) {
           equal |= a.charAt(i) ^ b.charAt(i);
       }
       return equal == 0;
    }

    上面的代碼是我根據原版(Scala)翻譯成 Java的,Scala 版本(最開始吸引程序猿石頭注意力的代碼)如下:

    def safeEqual(a: String, b: String) = {
      if (a.length != b.length) {
        false
      } else {
        var equal = 0
        for (i <- Array.range(0, a.length)) {
          equal |= a(i) ^ b(i)
        }
        equal == 0
      }
    }

    剛開始看到這段源碼感覺挺奇怪的,這個函數的功能是比較兩個字符串是否相等,首先“長度不等結果肯定不等,立即返回”這個很好理解。

    再看看後面的,稍微動下腦筋,轉彎下也能明白這其中的門道:通過異或操作1^1=0, 1^0=1, 0^0=0,來比較每一位,如果每一位都相等的話,兩個字符串肯定相等,最後存儲累計異或值的變量equal必定為 0,否則為 1。

    再細想一下呢?

    for (i <- Array.range(0, a.length)) {
      if (a(i) ^ b(i) != 0// or a(i) != b[i]
        return false
    }

    我們常常講性能優化,從效率角度上講,難道不是應該只要中途發現某一位的結果不同了(即為1)就可以立即返回兩個字符串不相等了嗎?(如上所示)

    這其中肯定有……

    再再細想一下呢?

    結合方法名稱 safeEquals 可能知道些眉目,與安全有關。

    本文開篇的代碼來自playframewok 里用來驗證cookie(session)中的數據是否合法(包含簽名的驗證),也是石頭寫這篇文章的由來。

    以前知道通過延遲計算等手段來提高效率的手段,但這種已經算出結果卻延遲返回的,還是頭一回!

    我們來看看,JDK 中也有類似的方法,如下代碼摘自 java.security.MessageDigest

    public static boolean isEqual(byte[] digesta, byte[] digestb) {
       if (digesta == digestb) return true;
       if (digesta == null || digestb == null) {
           return false;
       }
       if (digesta.length != digestb.length) {
           return false;
       }

       int result = 0;
       // time-constant comparison
       for (int i = 0; i < digesta.length; i++) {
           result |= digesta[i] ^ digestb[i];
       }
       return result == 0;
    }

    看註釋知道了,目的是為了用常量時間複雜度進行比較。

    但這個計算過程耗費的時間不是常量有啥風險? (腦海里響起了背景音樂:“小朋友,你是否有很多問號?”)

    真相大白

    再深入探索和了解了一下,原來這麼做是為了防止計時攻擊(Timing Attack)。(也有人翻譯成時序攻擊​)​

    計時攻擊(Timing Attack)

    計時攻擊是邊信道攻擊(或稱”側信道攻擊”, Side Channel Attack, 簡稱SCA) 的一種,邊信道攻擊是一種針對軟件或硬件設計缺陷,走“歪門邪道”的一種攻擊方式。

    這種攻擊方式是通過功耗、時序、電磁泄漏等方式達到破解目的。在很多物理隔絕的環境中,往往也能出奇制勝,這類新型攻擊的有效性遠高於傳統的密碼分析的數學方法(某百科上說的)。

    這種手段可以讓調用 safeEquals("abcdefghijklmn", "xbcdefghijklmn") (只有首位不相同)和調用 safeEquals("abcdefghijklmn", "abcdefghijklmn") (兩個完全相同的字符串)的所耗費的時間一樣。防止通過大量的改變輸入並通過統計運行時間來暴力破解出要比較的字符串。

    舉個,如果用之前說的“高效”的方式來實現的話。假設某個用戶設置了密碼為 password,通過從a到z(實際範圍可能更廣)不斷枚舉第一位,最終統計發現 p0000000 的運行時間比其他從任意a~z的都長(因為要到第二位才能發現不同,其他非 p 開頭的字符串第一位不同就直接返回了),這樣就能猜測出用戶密碼的第一位很可能是p了,然後再不斷一位一位迭代下去最終破解出用戶的密碼。

    當然,以上是從理論角度分析,確實容易理解。但實際上好像通過統計運行時間總感覺不太靠譜,這個運行時間對環境太敏感了,比如網絡,內存,CPU負載等等都會影響。

    但安全問題感覺更像是 “寧可信其有,不可信其無”。為了防止(特別是與簽名/密碼驗證等相關的操作)被 timing attack,目前各大語言都提供了相應的安全比較函數。各種軟件系統(例如 OpenSSL)、框架(例如 Play)的實現也都採用了這種方式。

    例如 “世界上最好的編程語言”(粉絲較少,評論區應該打不起架來)—— php中的:

    // Compares two strings using the same time whether they're equal or not.
    // This function should be used to mitigate timing attacks; 
    // for instance, when testing crypt() password hashes.
    bool hash_equals ( string $known_string , string $user_string )

    //This function is safe against timing attacks.
    boolean password_verify ( string $password , string $hash )

    其實各種語言版本的實現方式都與上面的版本差不多,將兩個字符串每一位取出來異或(^)並用或(|)保存,最後通過判斷結果是否為 0 來確定兩個字符串是否相等。

    如果剛開始沒有用 safeEquals 去實現,後續的版本還會通過打補丁的方式去修復這樣的安全隱患。

    例如 JDK 1.6.0_17 中的Release Notes[1]中就提到了MessageDigest.isEqual 中的bug的修復,如下圖所示:

    MessageDigest timing attack vulnerabilities

    大家可以看看這次變更的的詳細信息openjdk中的 bug fix diff[2]為:

    MessageDigest.isEqual計時攻擊

    Timing Attack 真的可行嗎?

    我覺得各大語言的 API 都用這種實現,肯定還是有道理的,理論上應該可以被利用的。 這不,學術界的這篇論文就宣稱用這種計時攻擊的方法破解了 OpenSSL 0.9.7 的RSA加密算法了。關於 RSA 算法的介紹可以看看之前本人寫的這篇文章。

    這篇Remote Timing Attacks are Practical[3] 論文中指出(我大致翻譯下摘要,感興趣的同學可以通過文末鏈接去看原文):

    計時攻擊往往用於攻擊一些性能較弱的計算設備,例如一些智能卡。我們通過實驗發現,也能用於攻擊普通的軟件系統。本文通過實驗證明,通過這種計時攻擊方式能夠攻破一個基於 OpenSSL 的 web 服務器的私鑰。結果證明計時攻擊用於進行網絡攻擊在實踐中可行的,因此各大安全系統需要抵禦這種風險。

    最後,本人畢竟不是專研完全方向,以上描述是基於本人的理解,如果有不對的地方,還請大家留言指出來。感謝。

    補充說明2:感謝正在閱讀文章的你,讓我還有動力繼續堅持更新原創。

    本人發文不多,但希望寫的文章能達到的目的是:佔用你的閱讀時間,就盡量能夠讓你有所收穫。

    如果你覺得我的文章有所幫助,還請你幫忙轉發分享,另外請別忘了點擊公眾號右上角加個星標,好讓你別錯過後續的精彩文章(微信改版了,或許我發的文章都不能推送到你那了)。

    ​原創真心不易,希望你能幫我個小忙唄,如果本文內容你覺得有所啟發,有所收穫,請幫忙點個“在看”唄,或者轉發分享讓更多的小夥伴看到。 ​ 參考資料:

    • Timing Attacks on RSA: Revealing Your Secrets through the Fourth Dimension
    • Remote Timing Attacks are Practical

     

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※為什麼 USB CONNECTOR 是電子產業重要的元件?

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    ※台北網頁設計公司全省服務真心推薦

    ※想知道最厲害的網頁設計公司"嚨底家"!

    ※推薦評價好的iphone維修中心

  • Express4.x之中間件與路由詳解及源碼分析,Express4.x之API:express,Express4.x之API:express

    Express4.x之中間件與路由詳解及源碼分析,Express4.x之API:express,Express4.x之API:express

    • Application.use()
    • Application.router()
    • express核心源碼模擬

     一、express.use()

    1.1app.use([path,] callback [, callback …])

    通過語法結構可以看到Application.use()參數分別有以下幾種情形:

    app.use(function(){...}); //給全局添加一个中間件
    app.use(path,function(){...}); //給指定路由path添加一个中間件
    app.use(function(){...}, function(){...}, ...); //給全局添加n个中間件
    app.use(path,function(){...},function(){...}, ...); //給指定路由path添加n个中間件

    關於path最簡單也是最常用的就是字符串類型(例:‘/abcd’);除了字符串Express還提供了模板和正則格式(例:’/abc?d‘, ‘/ab+cd‘, ‘/ab\*cd‘, ‘/a(bc)?d‘, ‘/\/abc|\/xyz/‘);除了單個的字符串和模板還可以將多個path作為一個數組的元素,然後將這個數組作為use的path,這樣就可以同時給多個路由添加中間件,詳細內容可以參考官方文檔:https://www.expressjs.com.cn/4x/api.html#path-examples。

    關於callbakc多個或單个中間件程序這已經再語法結構中直觀的體現出來了,這裏重點來看看回調函數的參數:

    app.use(function(req,res,next){...}); //必須提供的參數 
    app.use(function(err,req,res,next){...}); //錯誤中間件需要在最前面添加一個錯誤參數

    關於中間件的簡單應用:

    let express = require('./express');
    let app = express();
    app.use('/',function(req,res,next){
        console.log("我是一個全局中間件");
        next(); //每个中間件的最末尾必須調用next
    });
    
    app.use('/',function(err,req,res,next){
        console.log("我是一個全局錯誤中間,當發生錯誤是調用")    
        console.error(err.stack);
        res.status(500).send('服務出錯誤了!');
        //由於這個錯誤處理直接響應了客戶端,可以不再調用next,當然後面還需要處理一些業務的話也是可以調用next的
    });

    1.2簡單的模擬Express源碼實現Appliction.use()以及各個請求方法的響應註冊方法(這裏個源碼模擬路由概念還比較模糊,所以使用請求方法的響應註冊API,而沒有使用路由描述):

     1 //文件結構
     2 express
     3     index.js
     4 //源碼模擬實現
     5 let http = require("http");
     6 let url = require('url');
     7 function createApplication(){
     8     //app是一個監聽函數
     9     let app = (req,res) =>{
    10         //取出每一個層
    11         //1.獲取請求的方法
    12         let m = req.method.toLowerCase();
    13         let {pathname} = url.parse(req.url,true);
    14 
    15         //通過next方法進行迭代
    16         let index = 0;
    17         function next(err){
    18             //如果routes迭代完成還沒有找到,說明路徑不存在
    19             if(index === app.routes.length) return res.end(`Cannot ${m} ${pathname}`);
    20             let {method, path, handler} = app.routes[index++];//每次調用next就應該取下一個layer
    21             if(err){
    22                 if(handler.length === 4){
    23                     handler(err,req,res,next);
    24                 }else{
    25                     next(err);
    26                 }
    27             }else{
    28                 if(method === 'middle'){ //處理中間件
    29                     if(path === '/' || path === pathname || pathname.startsWith(path+'/')){
    30                         handler(req,res,next);
    31                     }else{
    32                         next();//如果這个中間件沒有匹配到,繼續通過next迭代路由容器routes
    33                     }
    34                 }else{ //處理路由
    35                     if( (method === m || method ==='all') && (path === pathname || path === '*')){ //匹配請求方法和請求路徑(接口)
    36                         handler(req,res);//匹配成功后執行的Callback
    37                     }else{
    38                         next();
    39                     }
    40                 }
    41             }
    42         }
    43         next();
    44     }
    45     app.routes = [];//路由容器
    46     app.use = function(path,handler){
    47         if(typeof handler !== 'function'){
    48             handler = path;
    49             path = '/';
    50         }
    51         let layer = {
    52             method:'middle', //method是middle就表示它是一个中間件
    53             path,
    54             handler
    55         }
    56         app.routes.push(layer);
    57     }
    58     app.all = function(path,handler){
    59         let layer = {
    60             method:'all',
    61             path,
    62             handler
    63         }
    64         app.routes.push(layer);
    65     }
    66     console.log(http.METHODS);
    67     http.METHODS.forEach(method =>{
    68         method = method.toLocaleLowerCase();
    69         app[method] = function (path,handler){//批量生成各個請求方法的路由註冊方法
    70             let layer = {
    71                 method,
    72                 path,
    73                 handler
    74             }
    75             app.routes.push(layer);
    76         }
    77     });
    78     //內置中間件,給req擴展path、qury屬性
    79     app.use(function(req,res,next){
    80         let {pathname,query} = url.parse(req.url,true);
    81         let hostname = req.headers['host'].split(':')[0];
    82         req.path = pathname;
    83         req.query = query;
    84         req.hostname = hostname;
    85         next();
    86     });
    87     //通過app.listen調用http.createServer()掛在app(),啟動express服務
    88     app.listen = function(){
    89         let server = http.createServer(app);
    90         server.listen(...arguments);
    91     }
    92     return app;
    93 }
    94 module.exports = createApplication;

    View Code

    測試模擬實現的Express:

     1 let express = require('./express');
     2 
     3 let app = express();
     4 
     5 app.use('/',function(req,res,next){
     6     console.log("我是一個全局中間件");
     7     next();
     8 });
     9 app.use('/user',function(req,res,next){
    10     console.log("我是user接口的中間件");
    11     next();
    12 });
    13 app.get('/name',function(req,res){
    14     console.log(req.path,req.query,req.hostname);
    15     res.end('zfpx');
    16 });
    17 app.post('/name',function(req,res){
    18     res.end('post name');
    19 });
    20 
    21 
    22 app.all("*",function(req,res){
    23     res.end('all');
    24 });
    25 
    26 app.use(function(err,req,res,next){
    27     console.log(err);
    28     next();
    29 });
    30 
    31 app.listen(12306);

    View Code

    在windows系統下測試請求:

     

     

    關於源碼的構建詳細內容可以參考這個視頻教程:app.use()模擬構建視頻教程,前面就已經說明過這個模式實現僅僅是從表面的業務邏輯,雖然有一點底層的雛形,但與源碼還是相差甚遠,這一部分也僅僅只是想幫助理解Express採用最簡單的方式表現出來。

    1.3如果你看過上面的源碼或自己也實現過,就會發現Express關於中間件的添加方式除了app.use()還有app.all()及app.METHOD()。在模擬源碼中我並未就use和all的差異做處理,都是採用了請求路徑絕對等於path,這種方式是all的特性,use的path實際表示為請求路徑的開頭:

    app.use(path,callback):path表示請求路徑的開頭部分。

    app.all(path,callback):paht表示完全等於請求路徑。

    app.METHOD(path,callback):並不是真的有METHOD這個方法,而是指HTTP請求方法,實際上表示的是app.get()、app.post()、app.put()等方法,而有時候我們會將這些方法說成用來註冊路由,這是因為路由註冊的確使用這些方法,但同時這些方法也是可以用作中間的添加,這在前一篇博客中的功能解析中就有說明(Express4.x之API:express),詳細見過後面的路由解析就會更加明了。

     二、express.router()

    2.1在實例化一個Application時會實例化一個express.router()實例並被添加到app._router屬性上,實際上這個app使用的use、all、METHOD時都是在底層調用了該Router實例上對應的方法,比如看下面這些示例:

     1 let express = require("express");
     2 let app = express();
     3 
     4 app._router.use(function(req,res,next){
     5     console.log("--app.router--");
     6     next();
     7 });
     8 
     9 app._router.post("/csJSON",function(req,res,next){
    10     res.writeHead(200);
    11     res.write(JSON.stringify(req.body));
    12     res.end();
    13 });
    14 
    15 app.listen(12306);

    上面示例中的app._router.use、app._router.post分別同等與app.use、app.post,這裏到這裏也就說明了上一篇博客中的路由與Application的關係Express4.x之API:express。

    2.2Express中的Router除了為Express.Application提供路由功能以外,Express也將它作為一個獨立的路由工具分離了出來,也就是說Router自身可以獨立作為一個應用,如果我們在實際應用中有相關業務有類似Express.Application的路由需求,可以直接實例化一個Router使用,應用的方式如下:

    let express = require('/express');
    let router = express.Router();
    //這部分可以詳細參考官方文檔有詳細的介紹

    2.3由於這篇博客主要是分析Express的中間件及路由的底層邏輯,所以就不在這裏詳細介紹某個模塊的應用,如果有時間我再寫一篇關於Router模塊的應用,這裏我直接上一份模擬Express路由的代碼以供參考:

    文件結構:

    express //根路徑
        index.js //express主入口文件
        application.js //express應用構造模塊
        router //路由路徑
            index.js //路由主入口文件
            layer.js //構造層的模塊
            route.js //子路由模塊

    Express路由系統的邏輯結構圖:

    模擬代碼(express核心源碼模擬):

    1 //express主入口文件
    2 let Application = require('./application.js');
    3 
    4 function createApplication(){
    5     return new Application();
    6 }
    7 
    8 module.exports = createApplication;

    index.js //express主入口文件

     1 //用來創建應用app
     2 let http = require('http');
     3 let url = require('url');
     4 
     5 //導入路由系統模塊
     6 let Router = require('./router');
     7 
     8 const methods = http.METHODS;
     9 
    10 //Application ---- express的應用系統
    11 function Application(){
    12     //創建一個內置的路由系統
    13     this._router = new Router();
    14 }
    15 
    16 //app.get ---- 實現路由註冊業務
    17 // Application.prototype.get = function(path,...handlers){
    18 //     this._router.get(path,'use',handlers);
    19 // }
    20 
    21 methods.forEach(method => {
    22     method = method.toLocaleLowerCase();
    23     Application.prototype[method] = function(path,...handlers){
    24         this._router[method](path,handlers);
    25     }
    26 });
    27 
    28 //app.use ---- 實現中間件註冊業務
    29 //這裏模擬處理三種參數模式:
    30 // -- 1個回調函數:callback
    31 // -- 多個回調函數:[callback,] callback [,callback...]
    32 // -- 指定路由的中間件:[path,] callback [,callback...]
    33 // -- 注意源碼中可以處理這三種參數形式還可以處理上面數據的數組形式,以及其他Application(直接將其他app上的中間件添加到當前應用上)
    34 Application.prototype.use = function(fn){
    35     let path = '/';
    36     let fns = [];
    37     let arg = [].slice.call(arguments);
    38     if(typeof fn !== 'function' && arg.length >= 2){
    39         if(typeof arg[0] !== 'string'){
    40             fns = arg;
    41         }else{
    42             path = arg[0];
    43             fns = arg.slice(1);
    44         }
    45     }else{
    46         fns = arg;
    47     }
    48     this._router.use(path,'use',fns);
    49 }
    50 
    51 Application.prototype.all = function(fn){
    52     let path = '/';
    53     let fns = [];
    54     let arg = [].slice.call(arguments);
    55     if(typeof fn !== 'function' && arg.length >= 2){
    56         if(typeof arg[0] !== 'string'){
    57             fns = arg;
    58         }else{
    59             path = arg[0];
    60             fns = arg.slice(1);
    61         }
    62       }else{
    63         fns = arg;
    64     }
    65     this._router.use(path,'all',fns);
    66 }
    67 
    68 //將http的listen方法封裝到Application的原型上
    69 Application.prototype.listen = function(){
    70     let server = http.createServer((req,res)=>{
    71         //done 用於當路由無任何可匹配項時調用的處理函數
    72         function done(){
    73             res.end(`Cannot ${req.url} ${req.method}`);
    74         }
    75         this._router.handle(req,res,done); //調用路由系統的handle方法處理請求
    76     });
    77     server.listen(...arguments);
    78 };
    79 
    80 module.exports = Application;

    application.js //express應用構造模塊

     1 //express路由系統
     2 const Layer = require('./layer.js');
     3 const Route = require('./route.js');
     4 
     5 const http = require('http');
     6 const methods = http.METHODS;
     7 
     8 const url = require('url');
     9 
    10 
    11 //路由對象構造函數
    12 function Router(){
    13     this.stack = [];
    14 }
    15 
    16 //router.route ---- 用於創建子路由對象route與主路由上層(layer)的關係
    17 //並將主路由上的層緩存到路由對象的stack容器中,該層建立路徑與子路由處理請求的關係
    18 Router.prototype.route = function(path){
    19     let route = new Route();
    20     let layer = new Layer(path,route.dispatch.bind(route));
    21     this.stack.push(layer);
    22     return route;
    23 }
    24 
    25 //router.get ---- 實現路由註冊
    26 //實際上這個方法調用router.route方法分別創建一個主路由系統層、一個子路由系統,並建立兩者之間的關係,詳細見Router.prototype.route
    27 //然後獲取子路由系統對象,並將回調函數和請求方法註冊在這個子路由系統上
    28 
    29 
    30 // Router.prototype.get = function(path,handlers){
    31 //     let route = this.route(path);
    32 //     route.get(handlers);
    33 // }
    34 
    35 methods.forEach(method =>{ 
    36     method = method.toLocaleLowerCase();
    37     //注意下面這個方法會出現內存泄漏問題,有待改進
    38     Router.prototype[method] = function(path, handlers){
    39         let route = this.route(path);
    40         route[method](handlers);
    41     }
    42 });
    43 
    44 //router.use ---- 實現中間件註冊(按照路由開頭的路徑匹配,即相對路由匹配)
    45 Router.prototype.use = function(path,routerType,fns){
    46     let router = this;
    47     fns.forEach(function(fn){
    48         let layer = new Layer(path,fn);
    49         layer.middle = true; //標記這個層為相對路由中間件
    50         layer.routerType = routerType;
    51         router.stack.push(layer);
    52     });
    53 }
    54 
    55 //調用路由處理請求
    56 Router.prototype.handle = function(req,res,out){
    57     let {pathname} = url.parse(req.url);
    58     let index = 0;
    59     let next = () => {
    60         if(index >= this.stack.length) return out();
    61         let layer = this.stack[index++];
    62         if(layer.middle && (layer.path === '/' || pathname === layer.path || pathname.startsWith(layer.path + '/'))){
    63             //處理中間件
    64             if(layer.routerType === 'use'){
    65                 layer.handle_request(req,res,next);
    66             }else if(layer.routerType === 'all' && layer.path === pathname){
    67                 layer.handle_request(req,res,next);
    68             }else{
    69                 next();
    70             }
    71         }else if(layer.match(pathname)){
    72             //處理響應--更準確的說是處理具體請求方法上的中間件或響應
    73             layer.handle_request(req,res,next);
    74         }else{
    75             next();
    76         }
    77     }
    78     next();
    79 }
    80 
    81 module.exports = Router;

    index.js //路由主入口文件

     1 //Layer的構造函數
     2 function Layer(path,handler){
     3     this.path = path; //當前層的路徑
     4     this.handler = handler;  //當前層的回調函數
     5 }
     6 
     7 //判斷請求方法與當前層的方法是否一致
     8 Layer.prototype.match = function(pathname){
     9     return this.path === pathname;
    10 }
    11 
    12 //調用當前層的回調函數handler
    13 Layer.prototype.handle_request = function(req,res,next){
    14     this.handler(req,res,next);
    15 }
    16 
    17 module.exports = Layer;

    layer.js //構造層的模塊

     1 //Layer的構造函數
     2 function Layer(path,handler){
     3     this.path = path; //當前層的路徑
     4     this.handler = handler;  //當前層的回調函數
     5 }
     6 
     7 //判斷請求方法與當前層的方法是否一致
     8 Layer.prototype.match = function(pathname){
     9     return this.path === pathname;
    10 }
    11 
    12 //調用當前層的回調函數handler
    13 Layer.prototype.handle_request = function(req,res,next){
    14     this.handler(req,res,next);
    15 }
    16 
    17 module.exports = Layer;

    route.js //子路由模塊

    測試代碼:

     1 let express = require('./express');
     2 let app = express();
     3 
     4 
     5 app.use('/name',function(req,res,next){
     6     console.log('use1');
     7     next();
     8 });
     9 app.use(function(req,res,next){
    10     console.log('use2-1');
    11     next();
    12 },function(req,res,next){
    13     console.log('use2-2');
    14     next();
    15 });
    16 
    17 app.all('/name',function(req,res,next){
    18     console.log('all-1');
    19     next();
    20 });
    21 app.all('/name/app',function(req,res,next){
    22     console.log('all-2');
    23     next();
    24 });
    25 
    26 app.get('/name/app',function(req,res){
    27     res.end(req.url);
    28 });
    29 // console.log(app._router.stack);
    30 app.listen(12306);

    View Code

    測試結果:

     

     

     

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

    ※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整

    南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!

    ※教你寫出一流的銷售文案?

    ※超省錢租車方案

  • Kubernetes-subpath的使用

    一、什麼是subpath

    為了支持單一個pod多次使用同一個volume而設計,subpath翻譯過來是子路徑的意思,如果是數據卷掛載在容器,指的是存儲卷目錄的子路徑,如果是配置項configMap/Secret,則指的是掛載在容器的子路徑。

     

    二、subpath的使用場景

    1、 1個pod中可以拉起多個容器,有時候希望將不同容器的路徑掛載在存儲卷volume的子路徑,這個時候需要用到subpath

    2、volume支持將configMap/Secret掛載在容器的路徑,但是會覆蓋掉容器路徑下原有的文件,如何支持選定configMap/Secret的每個key-value掛載在容器中,且不會覆蓋掉原目錄下的文件,這個時候也可以用到subpath

     

    三、subpath的使用

    1、存儲卷

        採用hostpath的方式創建PV,宿主機的映射目錄為/data/pod/volume5

    [root@k8s-master zhanglei]# cat pv-subpath.yaml 
    kind: PersistentVolume
    apiVersion: v1
    metadata:
      name: pv-subpath-05
      labels:
        release: stable
    spec:
      capacity:
        storage: 0.1Gi
      accessModes:
        - ReadWriteOnce
      persistentVolumeReclaimPolicy: Recycle
      hostPath:
        path: /data/pod/volume5                 # 宿主機的目錄

    [root@k8s-master zhanglei]# kubectl create -f pv-subpath.yaml  

    PV創建成功后,再創建PVC

    [root@k8s-master zhanglei]# cat pvc-subpath.yaml 
    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: pvc-subpath
      namespace: default
    spec:
     accessModes: ["ReadWriteOnce"]
     resources:
       requests: 
         storage: 0.05Gi
    [root@k8s-master zhanglei]# kubectl create -f pvc-subpath.yaml

    在pod中聲明並使用subpath

    [root@k8s-master zhanglei]# cat pod-subpath.yaml 
    apiVersion: v1
    kind: Pod
    metadata:
      name: pod-subpath-zltest
    spec:
        containers:
        - name: ubuntu-subpath-container
          image: ubuntu
          volumeMounts:
          - mountPath: /var/lib/ubuntu            # 容器1的掛載目錄
            name: subpath-vol
            subPath: ubuntutest                   # 宿主機volume5的子目錄1
        - name: nginx-subpath-container
          image: nginx
          volumeMounts:
          - mountPath: /var/www/nginx             # 容器2的掛載目錄
            name: subpath-vol
            subPath: nginxtest                   # 宿主機volume5的子目錄2 
        volumes:
        - name: subpath-vol
          persistentVolumeClaim:
            claimName: pvc-subpath               # PVC的名字

      [root@k8s-master zhanglei]# kubectl create -f pod-subpath.yaml

    [root@k8s-master zhanglei]# kubectl describe pod  pod-subpath-zltest 
    Name:         pod-subpath-zltest
    Namespace:    default
    Priority:     0
    Node:         k8s-master/192.168.126.129
    Start Time:   Fri, 29 May 2020 16:45:49 +0800
    Labels:       <none>
    Annotations:  cni.projectcalico.org/podIP: 10.122.235.235/32
                  cni.projectcalico.org/podIPs: 10.122.235.235/32
    Status:       Running
    IP:           10.122.235.235
    IPs:
      IP:  10.122.235.235
    Containers:
      ubuntu-subpath-container:
        Container ID:   docker://6e5cb30ee7e03b77d2ca22e4cd818ff326fa40836427fe17b1584646b4388dce
        Image:          ubuntu
        Image ID:       docker-pullable://ubuntu@sha256:747d2dbbaaee995098c9792d99bd333c6783ce56150d1b11e333bbceed5c54d7
        Port:           <none>
        Host Port:      <none>
        State:          Waiting
          Reason:       CrashLoopBackOff
        Last State:     Terminated
          Reason:       Completed
          Exit Code:    0
          Started:      Sun, 14 Jun 2020 22:38:11 +0800
          Finished:     Sun, 14 Jun 2020 22:38:11 +0800
        Ready:          False
        Restart Count:  558
        Environment:    <none>
        Mounts:
          /var/lib/ubuntu from subpath-vol (rw,path="ubuntutest")
          /var/run/secrets/kubernetes.io/serviceaccount from default-token-74s86 (ro)
      nginx-subpath-container:
        Container ID:   docker://95101741eb1b6aa4c1e53d8fc4ab8006e74fd2eb923eca211ca20a01edcd7630
        Image:          nginx
        Image ID:       docker-pullable://nginx@sha256:30dfa439718a17baafefadf16c5e7c9d0a1cde97b4fd84f63b69e13513be7097
        Port:           <none>
        Host Port:      <none>
        State:          Running
          Started:      Fri, 29 May 2020 16:47:14 +0800
        Ready:          True
        Restart Count:  0
        Environment:    <none>
        Mounts:
          /var/run/secrets/kubernetes.io/serviceaccount from default-token-74s86 (ro)
          /var/www/nginx from subpath-vol (rw,path="nginxtest")
    Conditions:
      Type              Status
      Initialized       True 
      Ready             False 
      ContainersReady   False 
      PodScheduled      True 
    Volumes:
      subpath-vol:
        Type:       PersistentVolumeClaim (a reference to a PersistentVolumeClaim in the same namespace)
        ClaimName:  pvc-subpath
        ReadOnly:   false
      default-token-74s86:
        Type:        Secret (a volume populated by a Secret)
        SecretName:  default-token-74s86
        Optional:    false
    QoS Class:       BestEffort
    Node-Selectors:  <none>
    Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                     node.kubernetes.io/unreachable:NoExecute for 300s
    Events:
      Type     Reason   Age                    From                 Message
      ----     ------   ----                   ----                 -------
      Normal   Pulled   21m (x555 over 16d)    kubelet, k8s-master  Successfully pulled image "ubuntu"
      Normal   Created  21m (x555 over 16d)    kubelet, k8s-master  Created container ubuntu-subpath-container
      Normal   Started  21m (x555 over 16d)    kubelet, k8s-master  Started container ubuntu-subpath-container
      Normal   Pulling  6m10s (x562 over 16d)  kubelet, k8s-master  Pulling image "ubuntu"
      Warning  BackOff  71s (x11744 over 16d)  kubelet, k8s-master  Back-off restarting failed container

    現在來驗證下在宿主機存儲卷的目錄下是否有2個子目錄,1個是ubuntutest用來掛載容器1的,另外1個是nginxtest用來掛載容器2的

    [root@k8s-master /]# cd data/pod/volume5
    [root@k8s-master volume5]# ls
    nginxtest ubuntutest
    [root@k8s-master volume5]# cd nginxtest/     # 可以看到是1個目錄,非文件
    [root@k8s-master nginxtest]#

    進入到容器中,掛載一個文件,驗證是否可以同步到存儲卷

    [root@k8s-master nginxtest]# kubectl exec -it pod-subpath-zltest -c nginx-subpath-container -- bash
    root@pod-subpath-zltest:/# cd /var/www/nginx
    root@pod-subpath-zltest:/var/www/nginx# ls
    nginx-test-subpath.txt
    [root@k8s-master volume5]# cd nginxtest/
    [root@k8s-master nginxtest]# ls
    nginx-test-subpath.txt

    可以看到容器1的目錄/var/www/nginx 和存儲卷的子目錄 nginxtest完成了映射,容器2類似,這裏不再贅述。

    2、配置項-configMap

    1)創建configMap

    [root@k8s-master consecret]# cat conf-subpath.yaml 
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: conf-subpath-zltest
      namespace: default
    data:
      example.property.1: hello      # key-value鍵值對
      example.property.2: world
      example.property.file: |-
        property.1=value-1
        property.2=value-2
        property.3=value-3

    2)在Pod中使用configMap

    [root@k8s-master consecret]# cat pod-conf-subpath.yaml 
    apiVersion: v1
    kind: Pod
    metadata:
      labels:
        purpose: test-configmap-volume
      name: pod-conf-testvolume
    spec:
      containers:
        - name: test-configmap-volume
          image: nginx
          volumeMounts:
            - name: config-volume
              mountPath: /etc/nginx/example.property.1       # 容器掛載目錄
              subPath: example.property.1                    # 將key名稱作為文件名,hello作為文件內容
      volumes:
        - name: config-volume
          configMap:
             name: conf-subpath-zltest      # 指定使用哪個CM
            
    [root@k8s-master consecret]# kubectl create -f pod-conf-subpath.yaml 
    [root@k8s-master consecret]# kubectl describe pod  pod-conf-testvolume 
    Name:         pod-conf-testvolume
    Namespace:    default
    Priority:     0
    Node:         k8s-master/192.168.126.129
    Start Time:   Wed, 03 Jun 2020 11:46:36 +0800
    Labels:       purpose=test-configmap-volume
    Annotations:  cni.projectcalico.org/podIP: 10.122.235.249/32
                  cni.projectcalico.org/podIPs: 10.122.235.249/32
    Status:       Running
    IP:           10.122.235.249
    IPs:
      IP:  10.122.235.249
    Containers:
      test-configmap-volume:
        Container ID:   docker://e2cf37cb24af32023eb5d22389545c3468104a4344c47363b5330addc40cb914
        Image:          nginx
        Image ID:       docker-pullable://nginx@sha256:883874c218a6c71640579ae54e6952398757ec65702f4c8ba7675655156fcca6
        Port:           <none>
        Host Port:      <none>
        State:          Running
          Started:      Wed, 03 Jun 2020 11:46:53 +0800
        Ready:          True
        Restart Count:  0
        Environment:    <none>
        Mounts:
          /etc/nginx/example.property.1 from config-volume (rw,path="example.property.1")  
          /var/run/secrets/kubernetes.io/serviceaccount from default-token-74s86 (ro)
    Conditions:
      Type              Status
      Initialized       True 
      Ready             True 
      ContainersReady   True 
      PodScheduled      True 
    Volumes:
      config-volume:
        Type:      ConfigMap (a volume populated by a ConfigMap)
        Name:      conf-subpath-zltest
        Optional:  false
      default-token-74s86:
        Type:        Secret (a volume populated by a Secret)
        SecretName:  default-token-74s86
        Optional:    false
    QoS Class:       BestEffort
    Node-Selectors:  <none>
    Tolerations:     node.kubernetes.io/not-ready:NoExecute for 300s
                     node.kubernetes.io/unreachable:NoExecute for 300s
    Events:          <none>

    在容器掛載路徑驗證下是否將configMap中example.property.1掛載在容器中,且是否會覆蓋掉原有的目錄

    root@pod-conf-testvolume:/# cd  /etc/nginx 
    root@pod-conf-testvolume:/etc/nginx# ls
    conf.d            fastcgi_params  koi-win    modules     scgi_params   win-utf
    example.property.1  koi-utf        mime.types    nginx.conf  uwsgi_params

    從上可以看到example.property.1已經掛載到容器中,且未對目錄原有的文件進行覆蓋

    root@pod-conf-testvolume:/etc/nginx# cd example.property.1 
    bash: cd: example.property.1: Not a directory
    root@pod-conf-testvolume:/etc/nginx# cat example.property.1 helloroot@pod-conf-testvolume:/etc/nginx# 

    從上可以驗證configMap的subpath用法支持將configMap中的每對key-value以key名稱作為文件名,value作為文件內容掛載到容器的目錄中。

    四、總結

    本文介紹了subpath分別在持久化存儲卷和配置項configMap中的使用,豐富了volume在pod中的使用場景。

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    網頁設計公司推薦不同的風格,搶佔消費者視覺第一線

    ※Google地圖已可更新顯示潭子電動車充電站設置地點!!

    ※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

    ※別再煩惱如何寫文案,掌握八大原則!

    網頁設計最專業,超強功能平台可客製化

  • 3dTiles 數據規範詳解[1] 介紹

    3dTiles 數據規範詳解[1] 介紹

    版權:轉載請帶原地址。https://www.cnblogs.com/onsummer/p/12799366.html @秋意正寒

    Web中的三維

    html5和webgl技術使得瀏覽器三維變成了可能。

    巧婦難為無米之炊,三維數據(三維模型)是三維可視化重要的一環,事實上就是:三維數據眾多,行業跨界廣。

    參考資料:http://www.bgteach.com/article/132

    three.js的各種加載器實現了大部分通用三維格式的加載,屏蔽了格式不同的數據結構差異。

    然而,這樣還是不能滿足日益增長的效果需求,比如場景一大,模型文件體積變大,解析所耗費的時間越來越長。

    webgl,包括所有gpu有關的圖形渲染編程,幾乎只認這樣的三維數據:頂點、頂點顏色、頂點法線、着色語言…

    所以,三維圖形界的通用格式:glTF應運而生,它面向終點,它按照圖形編程所需的格式來存儲數據,藉以二進制編碼提高傳輸速度。

    它不再使用面向對象的思維存儲三維模型、貼圖紋理,而是按顯卡的思維存儲,存的是頂點、法線、頂點顏色等最基礎的信息,只不過組織結構上進行了精心的設計。

    它面向終點,就意味着可編輯性差,因為渲染性能的提高犧牲了可編輯性,它不再像3ds、dae甚至是max、skp一樣容易編輯和轉換。

    事實上,大多數三維軟件提供了glTF格式的轉換,或多一步,或一步到位。

    地理真三維

    早年,地理的三維還處於地形三維上,即数字高程模型(DEM)提供地表的高度拉伸。柵格高程數據、等高線、不規則三角網等均是数字高程模型的具體案例。
    下圖是不規則三角網,也即所謂的三角面片(圖形渲染中很常見):

    隨着學科的融合、計算機技術和硬件的更新換代,使得有模型、有細節的真三維融入到GIS中成為了可能,或者說,計算機技術和硬件的升級,給GIS以更廣闊的視角觀察世界。

    cesium.js 號稱是 webgl 封裝的三維地理庫,是支持 gltf 模型的加載的。

    面對大規模精細三維數據的加載,還要照顧到GIS的各種坐標系統、分析計算,gltf這種單個模型的方案顯得力不從心。

    2016年,Cesium 團隊借鑒傳統2DGIS的地圖規範——WMTS,借鑒圖形學中的層次細節模型,打造出大規模的三維數據標準—— 3d-Tiles,中文譯名:三維瓦片。

    它在模型上利用了 gltf 渲染快的特點,對大規模的三維數據進行組織,包括層次細節模型、模型的屬性數據、模型的層級數據等。

    3dTiles的設計思想

    3dTiles 繼承了 gltf 的優點:貼合圖形渲染 API 的邏輯,討 GPU 喜愛,webgl 對其內部組織起來的三維模型數據,不需要轉換,可以直接渲染(glTF 的功勞)。

    關於 glTF 是如何嵌入到 3dTiles 中的,開篇不談,後續精講。

    我們區分一組概念:規範和實現。

    3dTiles 是一種規範,在規範的指導下,各種資源文件可以是獨立存在於硬盤中的目錄、文件,也可以以二進制形式寫入數據庫中。目前,3dTiles 的官方實現只有 “散列文件”,也就是文件、文件夾的形式存儲在硬盤中,有關如何存儲到數據庫中的討論,官方仍在進行中(截至發博客)。

    glTF 也是一種規範,它的數據文件不一定就是後綴名為 .gltf 的文件,也不一定只有一個文件(glTF 的文件還可以是二進制文件、紋理貼圖文件等,扯遠了哈)。
    在本文,會嚴格指明是數據還是數據標準,如果我說的是 “XXX文件(例如 Bird.glb 文件)” ,那就是在指特定的文件。

    3dTiles還有一個特點:那就是不記錄模型數據,只記錄各級“Tile”的邏輯關係,以及“Tile”自己的屬性信息。所謂的模型數據,是指三維模型的頂點、貼圖材質、法線、顏色等信息。邏輯關係是指,各級Tile是如何在空間中保持連續的,LOD是如何組織的。屬性信息就很簡單啦,門有門的生產商,窗戶有窗戶的使用年限等,往大了說,建築還有它自己的壽命、法人、施工單位等屬性信息。

    3dTiles的特點總結如下:

    • 三維模型使用了 glTF 規範,繼承它的渲染高性能
    • 除了嵌入的 glTF,3dTiles 自己 只記錄各級Tile的空間邏輯關係(如何構成整個3dtiles)和屬性信息,以及模型與屬性如何掛接在一起的信息

    我覺得你還是雲里霧裡的,下一節將展示3dTiles具體數據,說說3dTiles的組織結構,說說3dTiles中的”Tile”,也就是“三維瓦片數據”中的“瓦片”是什麼。

    3dTiles系列博客最終目錄:

    01 引入與博客目錄:3dTiles 數據規範詳解

    02 Tileset與Tile

    03 內嵌在瓦片文件中的兩大數據表

    04.1 B3dm 類型

    04.2 I3dm 類型

    04.3 Pnts 類型

    04.4 Cmpt 類型

    04.5 未發布的瓦片規範

    05 3dTiles強大的擴展能力

    06 優缺點

    07 與I3S比較

    本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

    【其他文章推薦】

    ※為什麼 USB CONNECTOR 是電子產業重要的元件?

    網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

    ※台北網頁設計公司全省服務真心推薦

    ※想知道最厲害的網頁設計公司"嚨底家"!

    ※推薦評價好的iphone維修中心