欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C# 使用Proxy代理請求資源的方法步驟

 更新時間:2019年03月25日 15:03:42   作者:BUTTERAPPLE  
這篇文章主要介紹了C# 使用Proxy代理請求資源的方法步驟,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

前言

這是上周在開發(fā) C# 中使用 Proxy 代理時開發(fā)的一些思考和實踐。主要需求是這樣的,用戶可以配置每次請求是否需要代理,用戶可以配置 HTTP代理,HTTPS代理和代理白名單。

還是太年輕

因為一直用的C# 網(wǎng)絡(luò)庫中的HttpWebRequest,所以自然而然先去找找看這個網(wǎng)絡(luò)庫有沒有封裝好我所需要的代理呀。果不其然,被我找到了。自從上次發(fā)現(xiàn)某些類對老版本不兼容后,每次在微軟官方文檔上找到都會翻到最后,查看一下支持的最低框架。

我需要的就是這個 Proxy 屬性,也就是說我最終在發(fā)送請求前,設(shè)置好這個 Proxy 屬性就可以了。先去看看 Proxy

The IWebProxy object to use to proxy the request. The default value is set by calling the Select property.

這樣的意思就是說我只要構(gòu)造一個WebProxy,然后賦值給 HttpWebRequest.Proxy就可以了。

看到了WebProxy 的構(gòu)造器,馬上鎖定了

因為我需要用戶傳的是 string ,所以直接這樣構(gòu)造就可以了。然后就是測試了,主管大佬寫的 Node.jsProxy代理 o_o 先來測試測試

npm install o_o -g

o_o

這樣就啟動全局安裝并啟動了代理,在控制臺上可以看到監(jiān)聽的是 8989 端口

 [Fact]
public void HttpProxy()
{
  var request = new DescribeAccessPointsRequest();
  client.SetHttpProxy("http://localhost:8989");

  var response = client.GetAcsResponse(request);
  Assert.NotNull(response.HttpResponse.Content);

  var expectValue = "HTTP/1.1 o_o";
  string actualValue;
  response.HttpResponse.Headers.TryGetValue("Via", out actualValue);
  Assert.Equal(expectValue, actualValue);
}

如果經(jīng)過了代理,頭部會出現(xiàn) "HTTP/1.1 o_o" 字段 ,經(jīng)過FT測試,是成功的。

本來一切都沒有問題的,除了我自己想的比較簡單外,直到我 Code Review 了一下組里開發(fā)JAVA 的人實現(xiàn)這個功能的 Pull Request ,我才發(fā)現(xiàn)我還真的是想的太簡單?。?!

開始重構(gòu)

首先發(fā)現(xiàn)的一點是,我連Constructor都用錯了,用ILSpy反編譯了一下,發(fā)現(xiàn)WebProxy(string,bool,string[])所作的事。

// System.Net.WebProxy
private static Uri CreateProxyUri(string address)
{
  if (address == null)
  {
    return null;
  }
  if (address.IndexOf("://") == -1)
  {
    address = "http://" + address;
  }
  return new Uri(address);
}

即使傳進去的是string,最后也是構(gòu)造成 Uri, 為什么會關(guān)注的這個呢?因為我發(fā)現(xiàn)有些Proxy地址是

http://username:password@localhost:8989 長這樣的,那么我如果直接以這種形式傳入到CreateProxy里面,它會自動給我分解,然后分Credentialproxy 傳入到網(wǎng)絡(luò)庫中嗎?接下來就是驗證的過程。

首先需要了解到的一個概念:Basic access authentication

In the context of an HTTP transaction, basic access authentication is a method for an HTTP user agent (e.g. a web browser) to provide a user name and password when making a request. In basic HTTP authentication, a request contains a header field of the form Authorization: Basic <credentials>, where credentials is the base64 encoding of id and password joined by a colon.

It is specified in RFC 7617 from 2015, which obsoletes RFC 2617 from 1999.

由于其不安全性,已在 RFC 中棄用了,轉(zhuǎn)而代之的是 TLS SSL 那些協(xié)議。

問題來了, HttpWebRequest 中支持Basic Authentication嗎?我們可以看到WebProxy中有一個構(gòu)造方法最后一個參數(shù)是 ICredential 的

是的,就是它,知道前因后果和不足后,我繼續(xù)去重構(gòu) Http Proxy 的代碼:

originProxyUri = new Uri(proxy);
if (!String.IsNullOrEmpty(originProxyUri.UserInfo))
{
  authorization = Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(originProxyUri.UserInfo));
  finalProxyUri = new Uri(originProxyUri.Scheme + "://" + originProxyUri.Authority);
  var userInfoArray = originProxyUri.UserInfo.Split(':');
  credential = new NetworkCredential(userInfoArray[0], userInfoArray[1]);

  httpRequest.WebProxy = new WebProxy(finalProxyUri, false, noProxy, credential);
}

先拆分出 UserInfo CredentialUri信息,然后分別重新構(gòu)造相應(yīng)的類型傳入到 WebProxy 中。上面也有一個坑,我之前還想用正則把usernamepassword 分別提取出去了,沒想到 Uri 已經(jīng)封裝好了,直接取里面的userinfo 信息。哈哈,省力了。

StackOverFlow上也有挺多關(guān)于如何傳入 CredentialProxy中,基本上用的也是這個方法,按理說這樣就完事了,直到我做了測試,我發(fā)現(xiàn)微軟這個Credential根本沒有起作用,如果是正確的話,會在 HEADER 中添加

Authorization: Basic <credentials> ,和上面那段測試代碼一樣,

[Fact]
public void HttpProxyWithCredential()
{
  DescribeAccessPointsRequest request = new DescribeAccessPointsRequest();
  client.SetHttpProxy("http://username:password@localhost:8989");
  var response = client.GetAcsResponse(request);

  var expectValue = "HTTP/1.1 o_o";
  string actualValue;
  response.HttpResponse.Headers.TryGetValue("Via", out actualValue);

  Assert.Equal(expectValue, actualValue);
  Assert.NotNull(response.HttpResponse.Content);
}

我去測試了發(fā)現(xiàn),這個頭部里面根本沒有加這個 Authorization 屬性啊,尷尬了,是官方文檔坑還是我使用不正確呢,基于此,想到了之前 主管 開發(fā)的那個 Proxy 代理 o_o ,我又去找了一個驗證 basic-authnode.js 代理服務(wù)器 basic-auth

npm install basic-auth
var http = require('http')
var auth = require('basic-auth')
var compare = require('tsscmp')

// Create server
var server = http.createServer(function (req, res) {
 var credentials = auth(req)

 // Check credentials
 // The "check" function will typically be against your user store
 if (!credentials || !check(credentials.name, credentials.pass)) {
  res.statusCode = 401
  res.setHeader('WWW-Authenticate', 'Basic realm="example"')
  res.end('Access denied')
 } else {
  res.end('Access granted')
 }
})

// Basic function to validate credentials for example
function check (name, pass) {
 var valid = true

 // Simple method to prevent short-circut and use timing-safe compare
 valid = compare(name, 'john') && valid
 valid = compare(pass, 'secret') && valid

 return valid
}

// Listen
server.listen(3000)

將上面那段 Js代碼打包成一個 js文件,然后執(zhí)行

node tets.js

該代理服務(wù)器監(jiān)聽 3000端口,我使用剛才那段代碼,果不其然,返回的是 401 ,這不是坑嗎,官方文檔上這樣說可以,然而都不行。

最后只能強制加上這個 Authorization 代碼

originProxyUri = new Uri(proxy);
if (!String.IsNullOrEmpty(originProxyUri.UserInfo))
{
  authorization = Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(originProxyUri.UserInfo));
  finalProxyUri = new Uri(originProxyUri.Scheme + "://" + originProxyUri.Authority);
  var userInfoArray = originProxyUri.UserInfo.Split(':');
  credential = new NetworkCredential(userInfoArray[0], userInfoArray[1]);

  httpRequest.WebProxy = new WebProxy(finalProxyUri, false, noProxy, credential);
  httpRequest.Headers.Add("Authorization", "Basic " + authorization);          
}

最后在測試經(jīng)過 3000 端口的代理服務(wù)器,確認(rèn)是沒問題的,把問題想得簡單的結(jié)果就是發(fā)了一個新版本后,還沒有下載,然而已經(jīng)發(fā)了新版本說,用戶您好,我們又有新版本了。尷尬。需要以此為鑒啊。

后記

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

最新評論