靜態(tài)網(wǎng)頁使用Node.js跨域代理服務(wù)

Node.js

1. 需求背景

公司網(wǎng)站的本地開發(fā)版之前一直都是部署在本地電腦上Tomcat容器里的日麸,好處就是本地搭建服務(wù)器環(huán)境接口無需做跨域請(qǐng)求處理傲诵,壞處就是后臺(tái)代碼的每次更新都需要拷貝一份至我的電腦覆蓋,并且本地環(huán)境與測(cè)試線環(huán)境數(shù)據(jù)仍然有所差異姨裸,在本地環(huán)境調(diào)試不便前方。

前天在與新入職的Java工程師討論如何分工協(xié)作的時(shí)候聊到了部署Tomcat容器到我本地的壞處,然后仔細(xì)想想我最近不是在學(xué)nodejs嘛,為何不學(xué)以致用在我本地用nodejs部署跨域代理服務(wù)呢?于是花了兩天零碎的時(shí)間研究了如何使用nodejs來實(shí)現(xiàn)靜態(tài)頁面的接口請(qǐng)求代理苹支。
在實(shí)現(xiàn)跨域之前先理清楚我想實(shí)現(xiàn)的什么樣的功能。

2. 跨域的幾種方式

靜態(tài)網(wǎng)站的里的ajax請(qǐng)求是相對(duì)路徑误阻,同一套代碼要在本地開發(fā)環(huán)境债蜜、測(cè)試線環(huán)境、大陸正式線究反、香港正式線部署寻定。所以請(qǐng)求不適合使用絕對(duì)路徑。

前端跨域

前端跨域的方式有兩種

  1. 通過script標(biāo)簽跨域
  2. 通過jsonp跨域

兩者的原理都是使用請(qǐng)求靜態(tài)資源文件的方式精耐,用回調(diào)函數(shù)的包裝把json數(shù)據(jù)返回前端狼速。從而騙過瀏覽器的跨域?qū)彶椤J褂眠@種方法來跨域意味著前端和后端的代碼都要根據(jù)跨域的要求來重構(gòu)一番卦停,并且只能發(fā)送GET請(qǐng)求,這樣的方式肯定是不可行的向胡,因?yàn)橹挥性诒镜亻_發(fā)時(shí)才需要跨域,代碼部署到線上服務(wù)器后就不需要跨域了惊完。
所以開始研究后端方案跨域僵芹。也有兩種。

后端跨域

  1. CORS跨域資源共享
  2. 跨域代理服務(wù)

CORS (Cross-Origin Resource Sharing)跨域資源共享小槐,它允許瀏覽器向跨源(協(xié)議 + 域名 + 端口)服務(wù)器拇派,發(fā)出XMLHttpRequest請(qǐng)求,從而克服了AJAX只能同源使用的限制凿跳。CORS需要瀏覽器和服務(wù)器同時(shí)支持,實(shí)現(xiàn)CORS通信的關(guān)鍵是服務(wù)器件豌。只要服務(wù)器實(shí)現(xiàn)了CORS接口,就可以跨源通信控嗜。

使用CORS來實(shí)現(xiàn)跨域仍然需要在目標(biāo)服務(wù)器的接口上配置跨域請(qǐng)求參數(shù)苟径,所以實(shí)現(xiàn)起來要前后端配合還是比較麻煩的。而且僅僅是測(cè)試線服務(wù)器需要跨域躬审,正式線服務(wù)器禁止跨域棘街,這樣子修改后,后臺(tái)代碼就會(huì)出現(xiàn)不一致承边。所以此方法也棄用遭殉。

跨域代理服務(wù),原理是把前端http請(qǐng)求發(fā)送給后臺(tái)的代理博助,讓代理代為轉(zhuǎn)發(fā)請(qǐng)求险污,從而不需要在瀏覽器上進(jìn)行跨域請(qǐng)求。代理獲取到響應(yīng)結(jié)果再轉(zhuǎn)發(fā)到前端。使用它的好處是目標(biāo)服務(wù)器上的接口代碼和前端代碼都不需要做任何更改蛔糯,只需開啟本地跨域代理服務(wù)即可拯腮。

每種跨域方式分析過后,覺得最可行的操作就是使用靜態(tài)資源代理服務(wù)來做前端跨域請(qǐng)求蚁飒。

3. 使用nodejs跨域代理服務(wù)

在nginx和nodejs間選擇了后者动壤,于是開始了在本地搭建http服務(wù)器和尋找合適的代理跨域中間件。

搭建了本地http服務(wù)后淮逻,具體怎么操作實(shí)現(xiàn)代理跨域其實(shí)還是沒多大思路的琼懊,于是呢就開始百度尋找案例來參考,了解了使用nodejs中間件跨域的大概思路爬早。

先是搭建起http服務(wù)器哼丈,對(duì)訪問主機(jī)地址的網(wǎng)絡(luò)請(qǐng)求進(jìn)行判斷,如果是api接口的請(qǐng)求時(shí)則使用中間件的代理服務(wù)進(jìn)行轉(zhuǎn)發(fā)筛严。讓中間件代為向目標(biāo)服務(wù)器發(fā)起請(qǐng)求醉旦,響應(yīng)結(jié)果再轉(zhuǎn)發(fā)至前端。

4. 代碼實(shí)現(xiàn)

文件結(jié)構(gòu)目錄大概如此,ROOT文件夾為網(wǎng)頁文件夾


項(xiàng)目文件目錄

1.創(chuàng)建項(xiàng)目文件夾并npm初始化文件夾

mkdir demo
cd demo
npm init -y

2.安裝node-http-proxy中間件
npm install http-proxy --save-dev

3.創(chuàng)建啟動(dòng)文件proxy.js

var PORT = 3000;//定義端口號(hào)
var tatgetPATH='http://www.a.com/'//目標(biāo)服務(wù)器地址
var http = require('http'); //引入http模塊
var url=require('url');  //引入url模塊
var fs=require('fs');  //引入文件模塊
var mine=require('./fileFormat').types;  //文件格式字典
var path=require('path'); //引入path模塊
var httpProxy = require('http-proxy');  //跨域代理中間件

var proxy = httpProxy.createProxyServer({
    target: tatgetPATH,   //接口地址
    // 下面的設(shè)置用于https
    // ssl: {
    //     key: fs.readFileSync('server_decrypt.key', 'utf8'),
    //     cert: fs.readFileSync('server.crt', 'utf8')
    // },
    // secure: false
});

var server = http.createServer(function (request, response) {
    var pathname = url.parse(request.url).pathname;

    //訪問根目錄時(shí)改為指向首頁文件
    if(pathname=='/'){
        pathname='index.html' 
    }
     // 指定根目錄
    var realPath = path.join("./ROOT", pathname);

    var ext = path.extname(realPath);
    ext = ext ? ext.slice(1) : 'unknown';

    //判斷如果是api接口訪問桨啃,則通過proxy轉(zhuǎn)發(fā)
    if(pathname.indexOf("./ROOT") > 0){
        // console.log('發(fā)起請(qǐng)求:',pathname)
        proxy.web(request, response);
        return;
    }

    fs.exists(realPath, function (exists) {
        if (!exists) {
            response.writeHead(404, {
                'Content-Type': 'text/plain'
            });

            response.write("This request URL " + pathname + " was not found on this server.");
            response.end();
        } else {
            fs.readFile(realPath, "binary", function (err, file) {
                if (err) {
                    response.writeHead(500, {
                        'Content-Type': 'text/plain'
                    });
                    response.end(err);
                } else {
                    var contentType = mine[ext] || "text/plain";
                    response.writeHead(200, {
                        'Content-Type': contentType
                    });
                    response.write(file, "binary");
                    response.end();
                }
            });
        }
    });
});
server.listen(PORT);

//代理服務(wù)執(zhí)行錯(cuò)誤的監(jiān)聽
proxy.on('error', function(err, req, res){
    res.writeHead(500, {
        'content-type': 'text/plain'
    });
    console.log(err);
    res.end('Something went wrong. And we are reporting a custom error message.');
});
console.log("Server runing at port: " + PORT + "."+tatgetPATH);

引入文件格式字典 fileFormat.js

exports.types = {
    "css": "text/css",
    "gif": "image/gif",
    "html": "text/html",
    "ico": "image/x-icon",
    "jpeg": "image/jpeg",
    "jpg": "image/jpeg",
    "js": "text/javascript",
    "json": "application/json",
    "pdf": "application/pdf",
    "png": "image/png",
    "svg": "image/svg+xml",
    "swf": "application/x-shockwave-flash",
    "tiff": "image/tiff",
    "txt": "text/plain",
    "wav": "audio/x-wav",
    "wma": "audio/x-ms-wma",
    "wmv": "video/x-ms-wmv",
    "xml": "text/xml",
    "woff": "application/x-woff",
    "woff2": "application/x-woff2",
    "tff": "application/x-font-truetype",
    "otf": "application/x-font-opentype",
    "eot": "application/vnd.ms-fontobject"
  };

代碼寫完后運(yùn)行proxy.js即可通過跨域代理服務(wù)來實(shí)現(xiàn)本地調(diào)用不同域服務(wù)器的接口了车胡。

5. 總結(jié)

跨域的解決方案有很多吨拍,具體選擇哪一種方案還是根據(jù)實(shí)際的情況來進(jìn)行分析。

以前還沒學(xué)習(xí)nodejs的時(shí)候网杆,遇到跨域問題能想到的解決方法就是使用ajax的jsonp,需要后端返回的接口加上回調(diào)函數(shù)羹饰,前端再通過通過函數(shù)對(duì)數(shù)據(jù)進(jìn)行接收。改起來十分之麻煩碳却。

前端若是懂得后端的一些知識(shí)队秩,便能夠使用更多的解決方案來解決問題。web開發(fā)中包括了前端和后端昼浦,能夠熟練使用兩端的技能馍资,才能夠在web開發(fā)中游刃有余。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末关噪,一起剝皮案震驚了整個(gè)濱河市鸟蟹,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌使兔,老刑警劉巖建钥,帶你破解...
    沈念sama閱讀 211,348評(píng)論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異虐沥,居然都是意外死亡熊经,警方通過查閱死者的電腦和手機(jī)泽艘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,122評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來镐依,“玉大人匹涮,你說我怎么就攤上這事』笨牵” “怎么了然低?”我有些...
    開封第一講書人閱讀 156,936評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長宏粤。 經(jīng)常有香客問我脚翘,道長灼卢,這世上最難降的妖魔是什么绍哎? 我笑而不...
    開封第一講書人閱讀 56,427評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮鞋真,結(jié)果婚禮上崇堰,老公的妹妹穿的比我還像新娘。我一直安慰自己涩咖,他們只是感情好海诲,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,467評(píng)論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著檩互,像睡著了一般特幔。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上闸昨,一...
    開封第一講書人閱讀 49,785評(píng)論 1 290
  • 那天蚯斯,我揣著相機(jī)與錄音,去河邊找鬼饵较。 笑死拍嵌,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的循诉。 我是一名探鬼主播横辆,決...
    沈念sama閱讀 38,931評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼茄猫!你這毒婦竟也來了狈蚤?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,696評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤划纽,失蹤者是張志新(化名)和其女友劉穎脆侮,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體阿浓,經(jīng)...
    沈念sama閱讀 44,141評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡他嚷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,483評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片筋蓖。...
    茶點(diǎn)故事閱讀 38,625評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡卸耘,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出粘咖,到底是詐尸還是另有隱情蚣抗,我是刑警寧澤,帶...
    沈念sama閱讀 34,291評(píng)論 4 329
  • 正文 年R本政府宣布瓮下,位于F島的核電站翰铡,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏讽坏。R本人自食惡果不足惜锭魔,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,892評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望路呜。 院中可真熱鬧迷捧,春花似錦、人聲如沸胀葱。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽抵屿。三九已至庆锦,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間轧葛,已是汗流浹背搂抒。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評(píng)論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留朝群,地道東北人燕耿。 一個(gè)月前我還...
    沈念sama閱讀 46,324評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像姜胖,于是被迫代替她去往敵國和親誉帅。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,492評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • 題目1.什么是同源策略? 同源策略(Same origin Policy): 瀏覽器出于安全方面的考慮右莱,只允許與本...
    FLYSASA閱讀 1,709評(píng)論 0 6
  • 什么是跨域 跨域蚜锨,是指瀏覽器不能執(zhí)行其他網(wǎng)站的腳本。它是由瀏覽器的同源策略造成的慢蜓,是瀏覽器對(duì)JavaScript實(shí)...
    他方l閱讀 1,061評(píng)論 0 2
  • 什么是跨域 跨域亚再,是指瀏覽器不能執(zhí)行其他網(wǎng)站的腳本。它是由瀏覽器的同源策略造成的晨抡,是瀏覽器對(duì)JavaScript實(shí)...
    Yaoxue9閱讀 1,288評(píng)論 0 6
  • 原文地址:原文地址 什么是跨域氛悬? 跨域是指一個(gè)域下的文檔或腳本試圖去請(qǐng)求另一個(gè)域下的資源则剃,這里跨域是廣義的。 廣義...
    C_Y大漁閱讀 1,256評(píng)論 1 13
  • 什么是跨域 跨域如捅,是指瀏覽器不能執(zhí)行其他網(wǎng)站的腳本棍现。它是由瀏覽器的同源策略造成的,是瀏覽器對(duì)JavaScript實(shí)...
    HeroXin閱讀 833評(píng)論 0 4