Fiddler助力微信開發除錯

廣州蘆葦科技web前端發表於2019-08-15

Fiddler是一個非常強大的代理工具,可以讓你的前端開發除錯更加方便。下面介紹在微信開發除錯方面的應用。

微信網頁開發中,由於有js介面安全域名和授權域名等的限制,導致部分功能需要部署到線上才能測試。通過代理可以實現本地除錯網站的所有功能。

配置代理規則

全站轉發可以這樣設定:Tools -> HOSTS

HOST配置

圖片中表示your.domain.com的請求全部轉發到127.0.0.1:8000。第二個引數的限制是:不能加協議、路徑或引數。

如果你的網站域名和介面域名是同一個,那就不能使用全站轉發了,需要html、css、js、websocket請求轉發到本地,介面呼叫請求則直接傳送到遠端伺服器。

可以使用自定義規則實現

自定義規則

上面圖片中的正規表示式和目標地址如下:

regex:^http://your.domain.com(?!/api|/swagger|/webjars|/configuration/ui)(.*)


http://localhost:8000$1
複製程式碼

本條規則表示:將your.domain.com下的http請求轉發到localhost:8000,其中/api/swagger/webjarsconfiguration/ui開頭的路徑不轉發。

目標地址表示式中的$1代表原始請求URL域名後面的字串,包括pathsearch

設定代理伺服器

開啟微信開發者工具,設定 -> 代理設定 -> 選擇手動設定代理Fiddler預設執行在127.0.0.1:8888

在真機上測試

在真機上測試本地微信網頁專案的步驟如下:

  1. 手機和電腦連線同一個區域網。
  2. 設定Fiddler允許遠端連線,Tools -> Options -> Connections -> 勾選Allow remote computers to connect

allow-remote

  1. 檢視電腦在區域網中的IP地址,命令列輸入ipconfig(windows)。

getIp

  1. 手機網路配置代理伺服器。

phone-config

到這裡,本篇文章的主要內容就結束了,如果你想了解更多關於Fiddler和代理工具的使用,可以參考我同事的文章代理工具Fiddler -除錯與替換介面狀態代理工具做微信專案的除錯配置。 如果你想了解使用nodejs如何實現上述以及更多自定義的功能,敬請往下閱讀。

nodejs實現代理伺服器

下文中,client表示客戶端(瀏覽器),proxy表示代理伺服器,server表示目標伺服器

HTTP

實現HTTP代理伺服器是非常簡單的,因為HTTP為明文傳輸,所以proxy只需要解析client的HTTP報文,再向server傳送相同的請求,server響應時,proxy將HTTP響應狀態,響應首部欄位和響應主體返回給client即可。

這裡可以使用nodejs的http模組實現

const http = require('http');
const { URL } = require('url');

let server = http.createServer((req, res) => {
  let {
    pathname,
    search,
    hostname,
    port
  } = new URL(req.url);

  console.log('http ', req.url);

  // 後端api呼叫請求直接傳送給遠端伺服器,除此之外的HTTP請求傳送給本地執行的埠
  if (!pathname.startsWith('/api')) {
    hostname = 'localhost';
    port = 8000; // 專案執行的埠
  }

  req.pipe(http.request({
    hostname,
    port,
    path: `${pathname}${search}`,
    method: req.method,
    headers: req.headers
  }, (response) => {
    res.writeHead(response.statusCode, response.statusMessage, response.headers);
    response.pipe(res);
  }));
});

server.listen(8888);

複製程式碼

HTTPS

只有HTTP代理伺服器是不夠的,因為不管是微信開發工具,還是瀏覽器,都有可能傳送HTTPS請求。比如微信開發者工具的登入和域名校驗就是使用的HTTPS與微信伺服器通訊的,如果不代理這部分流量是無法正常執行微信開發者工具的。

HTTPS因為報文加密的原因,proxy不能解析報文後偽裝client傳送請求。最常見的解決方案是web隧道,proxy建立和client、server的TCP連線,之後盲轉發兩端的資料。

建立web隧道的方式之一是使用HTTP的CONNECT方法,實際上客戶端(瀏覽器)設定了代理伺服器後,client發出的HTTPS請求是不同的,它首先會使用CONNECT方法傳送HTTP請求,請求proxy建立連線,這是proxy能代理HTTPS的關鍵。

client請求proxy與server建立TCP連線的HTTP報文如下:

CONNECT your.domain:443 HTTP/1.1
Host: your.domain:443
Connection: keep-alive
User-Agent: M....

複製程式碼

proxy在與server建立TCP連線後,按照約定,需要200 Connection Established響應,響應首部欄位可自定義:

HTTP/1.1 200 Connection Established
Connection: close

複製程式碼

所以http伺服器就可以代理https請求。實際上,按照上面的原理http伺服器能夠代理很多其他協議的流量。

https代理伺服器需要使用http和net模組,對上面的http代理的程式碼擴充套件即可

server.on('connect', (req, clientSocket) => {
  let {
    port,
    hostname
  } = new URL(`http://${req.url}`);

  console.log('https', req.url);

  let serverSocket = net.connect(port || 80, hostname, () => {
    clientSocket.write(
      `HTTP/1.1 200 Connection Established
Connection: close

`
    );

    clientSocket.pipe(serverSocket);
    serverSocket.pipe(clientSocket);
  });
});
複製程式碼

從實現方式可以看出來,這種代理伺服器是無法正常獲取和更改通訊雙方的資料的。如果要實現能監聽和更改通訊資料的HTTPS代理伺服器,可以使用自簽名證書實現,這裡不做探究。

websocket

本地開發的專案往往有熱更新功能,而熱更新的通訊依靠websocket,所以websocket代理也是必不可少的。websocket的連線也是用HTTP建立起來的。 如果根據我們之前瞭解的websocket知識,client會向伺服器傳送協議升級請求(請求報文中包含特殊的請求首部欄位),伺服器響應101 Switching Protocols,之後的資料則轉為websocket協議傳送。根據以上流程,同樣只需要對http伺服器程式碼擴充即可,我們很容易寫出如下程式碼:

server.on('upgrade', (req, clientSocket) => {
  let {
    pathname,
    search,
    hostname,
    port
  } = new URL(req.url);

  console.log('websocket', req.url);

  let request = http.request({
    pathname: 'localhost',
    port: 8000, // 專案執行的埠
    method: req.method,
    headers: req.headers
  });

  req.pipe(request);

  request.on('upgrade', (response, serverSocket) => {
    let resStr = 'HTTP/1.1 101 Switching Protocols\r\n';

    for (let [key, value] of Object.entries(response.headers)) {
      resStr += `${key}: ${value}\r\n`;
    }

    resStr += '\r\n';

    clientSocket.write(resStr);
    clientSocket.pipe(serverSocket);
    serverSocket.pipe(clientSocket);
  });
});

server.listen(8888)
複製程式碼

上面的寫法實際上是反向代理伺服器的寫法。即,瀏覽器直接建立到ws://localhost:8888的請求,該代理伺服器是能夠將請求轉發到8000埠的,但當瀏覽器設定了代理伺服器後,傳送websocket請求和沒設定前是不同的,它同樣會先向proxy請求建立連線,所以代理websocket請求和代理https請求程式碼是一樣的,我們在connect事件中做好區分即可。

server.on('connect', (req, clientSocket) => {
  let {
    port,
    hostname
  } = new URL(`http://${req.url}`);

  console.log('https', req.url);

  // websocket請求傳送到本地8000埠
  if (req.url === 'your.domain.com:80') {
    port = 8000; // 專案執行的埠
    hostname = 'localhost';
  }

  let serverSocket = net.connect(port || 80, hostname, () => {
    clientSocket.write(
      `HTTP/1.1 200 Connection Established
Connection: close

`
    );

    console.log(req.url, 'connect');

    clientSocket.pipe(serverSocket);
    serverSocket.pipe(clientSocket);
  });
});
複製程式碼

經過以上三步,一個帶有完整功能的代理伺服器就寫好了,想要實現自定義功能,無非是在請求報文識別和server響應報文篡改上做文章,盡情發揮你的創造力吧。

原文連結

【作者簡介】:葉茂,蘆葦科技web前端開發工程師,代表作品:口紅挑戰網紅小遊戲、服務端渲染官網、微信小程式粒子系統。擅長網站建設、公眾號開發、微信小程式開發、小遊戲、公眾號開發,專注於前端領域框架、互動設計、影像繪製、資料分析等研究。 一起並肩作戰: yemao@talkmoney.cn 訪問 www.talkmoney.cn 瞭解更多

相關文章