有个项目需要调用第三方SDK,而SDK获取服务器的已安装的特殊打印机列表返回给调用方。
但我不想依赖这个SDK,因为这个SDK是使用.NET Framework编写的,而我的项目是使用.NET Core编写的,并且想要部署在Docker容器内运行。
于是反编译了SDK,查看源代码,看到该SDK调用了一个URL获取结果。
而这个URL是本地URL,http://localhost开头的,此时我才知道这个SDK所对应的软件在服务器提供了一个本地的Web服务。
于是我在项目里移除这个SDK,直接调用URL。
但获取结果失败了,提示“响应状态代码不指示成功: 401 (Unauthorized)。”。而直接浏览器访问这个URL却成功返回结果。
刚开始一脸懵逼,不知道原来是没有认证的原因在作梗...
很习惯性的就祭出Fiddler监听这个URL,在浏览器里直接访问这个URL,在Fiddler却看到这个URL被请求了3次。
当时没有在意,直接拿到Request Header,塞到HttpClient的Header里,再次请求,还是报错。
重新粗略地看Fiddler,这时才留意到重复请求3次的问题。
我以为是请求内重定向,设置AllowAutoRedirect为true,再次请求,又报错。
又重新仔细地逐条看Fiddler,第二条在Request Header出现了Authorization: Negotiate xxxxxxxxx。
这才知道用了Authorization认证,于是我根据URL端口查到Windows的端口占用列表,顺便找到了该端口占用所对应的PID。
找到PID就找到了进程,从而找到进程所在的文件夹目录,查看它的config配置文件,从配置描述来看,这个Web服务更准确来讲是一个WCF服务。
它使用了security节点:
<security mode="TransportCredentialOnly"> <transport clientCredentialType="Windows"></transport> </security>
我设置UseDefaultCredentials为true,再次请求,成功获取结果。
这是HttpClient请求本地WCF服务 最终代码:
private static async void Test() { Random rand = new Random(); var r = rand.Next(10000, 99999); string url = "http://localhost:8080/WebPrintService/GetClientPrinters?rand=" + r; var handler = new HttpClientHandler(); //handler.AllowAutoRedirect = true; //handler.UseDefaultCredentials = true; //handler.PreAuthenticate = true; HttpClient httpClient = new HttpClient(handler); //HttpRequestMessage requestMessage = new HttpRequestMessage(); //requestMessage.RequestUri = new Uri(url); //requestMessage.Method = HttpMethod.Get; //requestMessage.Headers.CacheControl.MaxAge = TimeSpan.Zero; //requestMessage.Headers.Authorization=new AuthenticationHeaderValue(); //requestMessage.Headers.Accept.Clear(); //requestMessage.Headers.Accept.ParseAdd("application/json, text/javascript, */*; q=0.01"); //requestMessage.Headers.AcceptEncoding.Clear(); //requestMessage.Headers.AcceptEncoding.ParseAdd("gzip, deflate"); //requestMessage.Headers.AcceptLanguage.Clear(); //requestMessage.Headers.AcceptLanguage.ParseAdd("zh-CN"); //requestMessage.Headers.UserAgent.Clear(); //requestMessage.Headers.UserAgent.ParseAdd("Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko"); //requestMessage.Headers.Add("X-Requested-With", "XMLHttpRequest"); //var responseMessage = await httpClient.SendAsync(requestMessage); //var result = await responseMessage.Content.ReadAsStringAsync(); var result = await httpClient.GetStringAsync(url); JsonConvert.DeserializeObject<PrinterInfo>(jsonString); //第二种写法,.NET Framework自带,无须为了HttpClient使用NuGet引入Microsoft.Net.Http包 //WebRequest request = WebRequest.Create(url); //request.Method = "GET"; //request.UseDefaultCredentials = true; //WebResponse response = request.GetResponse(); //var stream = response.GetResponseStream(); //using (var streamReader = new StreamReader(stream)) //{ // using (var textReader = new JsonTextReader(streamReader)) // { // var serializer = new JsonSerializer(); // var result = serializer.Deserialize<List<PrinterInfo>>(textReader); // } //} }