I'm trying to GET string from website with HttpRequest.
It works fine, but when I want to implement proxy then it always returns 400 Bad Request.
Proxy works because I can get response from www.google.com when using it. But other websites I tried doesn't work.
For security reasons I can't share here my API but it looks something like this -> https://mywebsite.com/api/email-details?email=email#gmail.com
And this link show you result string that I want to get in my application.
I can get without proxy, proxy is free from internet (maybe that can be problem because web blocked it or something?)
My code
var url = "https://mywebsite.com/api/email-details?email=email#gmail.com";
var httpRequest = (HttpWebRequest)WebRequest.Create(url);
httpRequest.Proxy = new WebProxy
{
Address = new Uri($"http://199.19.226.12:80"),
};
var httpResponse = (HttpWebResponse)httpRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Thank you very much for all answers, I tried to figure out for so long. Have a great day :)
Related
I'm writing a C# application that interacts with the SAP B1 Service Layer and I'm attempting to Login through a HTTP POST call, using JSON for the body.
If I send over the login request using POSTMAN, it logs me in fine and I receive the session cookie as expected. When I send over the JSON through my C# app, I receive a 500 error - I have absolutely no idea why. I have another method that sends over a request for a specific item which returns a 401 - Unauthorized so I know it's hitting the Service Layer.
Below is the code in the method so far.
var request = (HttpWebRequest)WebRequest.Create("https://172.16.101.38:50000/b1s/v1/Login");
request.ContentType = "application/json";
request.Method = "POST";
request.ServerCertificateValidationCallback = AcceptAllCertifications;
using (var streamWriter = new StreamWriter(request.GetRequestStream()))
{
string json = new JavaScriptSerializer().Serialize(new
{
UserName = "user",
Password = "pass",
CompanyDB = "db"
});
streamWriter.Write(json);
}
var response = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(response.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
And the "AcceptAllCertifications" method is as follows:
public bool AcceptAllCertifications(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certification,
System.Security.Cryptography.X509Certificates.X509Chain chain, System.Net.Security.SslPolicyErrors sslPolicyErrors)
{
return true;
}
If I don't include this method, I get a "Could not establish a trust relationship for the SSL/TLS secure channel..." error. In POSTMAN, I have to ensure "SSL Certificate verification" is OFF so that I can access the Service Layer.
I know the JSON produced is valid as I've tested it in POSTMAN.
Anyone run into this before and managed to figure out how to rectify this?
Add below line in your request.
request.ServicePoint.Expect100Continue = false;
Here is a link to the solution I've had to implement:
SAP Consume OData Services
So instead of trying to access everything through JSON, I've had to take some code from here which creates a Service Layer instance and logs in through a method implemented in there.
Very fiddly to get working at first, but once it is working it's pretty solid.
I am using import.io to perform some simple query. I need to automate the calls because of the quantity of queries, therefore I am writing a c# client to run all of them.
I can use the API query "magic string" as template to build my queries, if I manually paste them in a browser I see the JSon of the response.
Calling the urls by code instead I always get the 401 unauthorized error.
I tried to set the url to a web browser control, but it reports that site cannot be accessed.
callingApi is a string with the full url, composed as such (instead of § I have the url to be scraped):
https://api.import.io/store/connector/(connector code)/_query?input=webpage/url:§_apikeyadmin=(my key)
(same problem with _apikey instead of _apikeyadmin)
I tried
WebRequest r = WebRequest.Create(callingApi);
r.Method = "GET";
using (var sr = r.GetResponse().GetResponseStream())
{
using (var reader = new StreamReader(sr))
{
var content = reader.ReadToEnd();
}
}
and also
HttpClient client = new HttpClient();
client.BaseAddress = new Uri(callingApi);
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = client.GetAsync(callingApi).Result;
if (response.IsSuccessStatusCode)
... here I have error 401
Any advice please?
I'm building a client-server desktop app in C# and RestSharp seems to be tripping my program up somewhere. The oddest thing is that other POSTs are working to the same Node.js server app.
Here's my code using RestSharp:
RestClient client = new RestClient("http://"+Configuration.server);
RestRequest request = new RestRequest("sync", Method.POST);
request.AddParameter("added", Indexer.getAddedJson());
request.AddParameter("removed", Indexer.getRemovedJson());
RestResponse<StatusResponse> response = (RestResponse<StatusResponse>)client.Execute<StatusResponse>(request);
e.Result = response.Data;
This doesn't work - and by that I mean it doesn't make a call to the server at all. I've verified this using Fiddler too.
But this does work:
using (var wb = new WebClient())
{
var data = new NameValueCollection();
data["added"] = Indexer.getAddedJson();
data["removed"] = Indexer.getRemovedJson();
var resp = wb.UploadValues("http://" + Configuration.server + "/sync", "POST", data);
}
I can't figure out for the life of me what's going on. I don't want to stop using RestSharp just for this request, other POST requests are working just fine!
It's not a deserialization problem, because response.Content is null. I'm getting a StatusResponse in the other calls as well so this is probably not the issue.
I am trying to parse the HTML code of the page at http://odds.bestbetting.com/horse-racing/today in order to have a list of races, etc.
The problem is I am not being able to retrieve the HTML code of the page. Here is the C# code of the function:
public static string Http(string url) {
Uri myUri = new Uri(url);
// Create a 'HttpWebRequest' object for the specified url.
HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(myUri);
myHttpWebRequest.AllowAutoRedirect = true;
// Send the request and wait for response.
HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
var stream = myHttpWebResponse.GetResponseStream();
var reader = new StreamReader(stream);
var html = reader.ReadToEnd();
// Release resources of response object.
myHttpWebResponse.Close();
return html;
}
When I execute the program calling the function it throws an exception on
HttpWebResponse myHttpWebResponse =
(HttpWebResponse)myHttpWebRequest.GetResponse();
which is:
Cannot handle redirect from HTTP/HTTPS protocols to other dissimilar ones.
I have read this question but I don't seem to have the same problem.
I've also tried iguring something out sniffing the traffic with fiddler but can't see anything to where it redirects or something similar. I just have extracted these two possible redirections: odds.bestbetting.com/horse-racing/2011-06-10/byCourse
and odds.bestbetting.com/horse-racing/2011-06-10/byTime , but querying them produces the same result as above.
It's not the first time I do something like this, but I'm really lost on this one. Any help?
Thanks!
I finally found the solution... it effectively was a problem with the headers, specifically the User-Agent one.
I found after lots of searching a guy having the same problem as me with the same site. Although his code was different the important bit was that he set the UserAgent attribute of the request manually to that of a browser. I think I had done this before but I may had done it pretty bad... sorry.
The final code if it is of interest to any one is this:
public static string Http(string url) {
if (url.Length > 0)
{
Uri myUri = new Uri(url);
// Create a 'HttpWebRequest' object for the specified url.
HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(myUri);
// Set the user agent as if we were a web browser
myHttpWebRequest.UserAgent = #"Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.0.4) Gecko/20060508 Firefox/1.5.0.4";
HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
var stream = myHttpWebResponse.GetResponseStream();
var reader = new StreamReader(stream);
var html = reader.ReadToEnd();
// Release resources of response object.
myHttpWebResponse.Close();
return html;
}
else { return "NO URL"; }
}
Thank you very much for helping.
There can be a dozen probable causes for your problem.
One of them is that the redirect from the server is pointing to an FTP site, or something like that.
It can also being that the server require some headers in the request that you're failing to provide.
Check what a browser would send to the site and try to replicate.
I created RESTful webservice (WCF) where I check credentials on each request. One of my clients is Android app and everything seems to be great on server side. I get request and if it's got proper header - I process it, etc..
Now I created client app that uses this service. This is how I do GET:
// Create the web request
var request = WebRequest.Create(Context.ServiceURL + uri) as HttpWebRequest;
if (request != null)
{
request.ContentType = "application/json";
// Add authentication to request
request.Credentials = new NetworkCredential(Context.UserName, Context.Password);
// Get response
using (var response = request.GetResponse() as HttpWebResponse)
{
// Get the response stream
if (response != null)
{
var reader = new StreamReader(response.GetResponseStream());
// Console application output
var s = reader.ReadToEnd();
var serializer = new JavaScriptSerializer();
var returnValue = (T)serializer.Deserialize(s, typeof(T));
return returnValue;
}
}
}
So, this code get's my resource and deserializes it. As you see - I'm passing credentials in my call.
Then when debugging on server-side I noticed that I get 2 requests every time - one without authentication header and then server sends back response and second request comes bach with credentials. I think it's bad for my server - I'd rather don't make any roundtrips. How should I change client so it doesn't happen? See screenshot of Fiddler
EDIT:
This is JAVA code I use from Android - it doesn't do double-call:
MyHttpResponse response = new MyHttpResponse();
HttpClient client = mMyApplication.getHttpClient();
try
{
HttpGet request = new HttpGet(serviceURL + url);
request.setHeader(new BasicHeader(HTTP.CONTENT_TYPE, "application/json"));
request.addHeader("Authorization", "Basic " + Preferences.getAuthorizationTicket(mContext));
ResponseHandler<String> handler = new BasicResponseHandler();
response.Body = client.execute(request, handler);
response.Code = HttpURLConnection.HTTP_OK;
response.Message = "OK";
}
catch (HttpResponseException e)
{
response.Code = e.getStatusCode();
response.Message = e.getMessage();
LogData.InsertError(mContext, e);
}
The initial request doesn't ever specify the basic header for authentication. Additionally, since a realm is specified, you have to get that from the server. So you have to ask once: "hey, I need this stuff" and the server goes "who are you? the realm of answering is 'secure area'." (because realm means something here) Just because you added it here:
request.Credentials = new NetworkCredential(Context.UserName, Context.Password);
doesn't mean that it's going to be for sure attached everytime to the request.
Then you respond with the username/password (in this case you're doing BASIC so it's base64 encoded as name:password) and the server decodes it and says "ok, you're all clear, here's your data".
This is going to happen on a regular basis, and there's not a lot you can do about it. I would suggest that you also turn on HTTPS since the authentication is happening in plain text over the internet. (actually what you show seems to be over the intranet, but if you do go over the internet make it https).
Here's a link to Wikipedia that might help you further: http://en.wikipedia.org/wiki/Basic_access_authentication
Ok, I got it. I manually set HttpHeader instead of using request.Credentials
request.Headers.Add(HttpRequestHeader.Authorization, "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes(Context.UserName + ":" + Context.Password)));
Now I see only single requests as expected..
As an option you can use PreAuthenticate property of HttpClientHandler. This would require a couple of lines more
var client = new HttpClient(new HttpClientHandler
{
Credentials = yourCredentials,
PreAuthenticate = true
});
With using this approach, only the first request is sent without credentials, but all the rest requests are OK.