CORS Post request working locally but not on server - javascript

I have two projects in the same solution. One is an ASP.NET MVC project and the other is a Web API project. On my local machine the MVC project is running on http://localhost:2302/ I have enabled CORS in the Web API project using the following code in the WebApiConfig.cs file:
namespace WebServices
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
var cors = new EnableCorsAttribute("http://localhost:2302", "*", "*");
config.EnableCors(cors);
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute("ActionApi", "{controller}/{action}/");
}
}
}
I also have a controller where I have a controller like the following:
namespace WebServices.Controllers
{
public class UploadController : ApiController
{
private readonly IUploadManager _uploadManager;
public UploadController(IUploadManager uploadManager)
{
_uploadManager = uploadManager;
}
[HttpPost]
public async Task<HttpResponseMessage> UploadImage()
{
var result = await _uploadManager.UploadImage(Request);
return result.Success
? Request.CreateResponse(HttpStatusCode.OK, result)
: Request.CreateResponse(HttpStatusCode.Conflict);
}
}
}
UploadImage method exists inside a repository class where I have the upload logic there. Finally I call my service using the XMLHttpRequest JavaScript object like the following:
var xhr = new window.XMLHttpRequest();
var uploadPercent;
xhr.upload.addEventListener('progress', function (event) {
var percent = Math.floor((event.loaded / event.total) * 100);
uploadPercent = percent;
}, false);
xhr.onreadystatechange = function (event) {
if (event.target.readyState === event.target.DONE) {
if (event.target.status !== 200) {
console.log('error in uploading image');
} else {
var status = JSON.parse(event.target.response);
var imageGuid = status.returnId;
var imageUrl = status.returnString;
}
}
};
xhr.open('post', 'http://localhost:4797/Upload/UploadImage', true);
var data = new FormData();
var files = $('#uploadInput')[0].files;
for (var i = 0; i < files.length; i++) {
data.append('file' + i, files[i]);
}
xhr.send(data);
The above code works good when I test it on my local machine. But when I deploy it on an actual server it does not (Of course I have changed all the links to the respective links for my domain - also the projects are deployed separately but on the same server). When the OPTIONS request is sent I receive 400 Bad Request status code. I have read a lot of information on the internet but nothing seems to help me. This is the request sent by the browser:
Accept:*/*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:en-US,en;q=0.8,el;q=0.6
Access-Control-Request-Headers:content-type
Access-Control-Request-Method:POST
Connection:keep-alive
Host:api.example.com
Origin:http://example.com
Referer:http://example.com/Account/ExtraDetails/91a832ee-496c-46a7-ac4b-dfb89bbc8fc5
User-Agent:Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36
and the response received:
Cache-Control:no-cache
Content-Length:69
Content-Type:application/json; charset=utf-8
Date:Mon, 15 Dec 2014 22:42:11 GMT
Expires:-1
Pragma:no-cache
Server:Microsoft-IIS/7.5
X-AspNet-Version:4.0.30319
X-Powered-By:ASP.NET
I noticed that no Access-Control-Allow-Origin header is created in the response when the application is deployed but as far as I know it should be. Do I need to do any further configuration on the server or am I missing something? Thank you in advance.

You don't seem to be handling the preflight Options requests.
Web API needs to respond to the Options request in order to confirm that it is indeed configured to support CORS.
To handle this, all you need to do is send an empty response back. You can do this inside your actions, or you can do it globally like this:
protected void Application_BeginRequest()
{
if (Request.Headers.AllKeys.Contains("Origin") && Request.HttpMethod == "OPTIONS")
{
Response.Flush();
}
}
This extra check was added to ensure that old APIs that were designed to accept only GET and POST requests will not be exploited. Imagine sending a DELETE request to an API designed when this verb didn't exist. The outcome is unpredictable and the results might be dangerous.
Also I suggest enabling Cors by web.config instead of config.EnableCors(cors);
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
<add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE, OPTIONS" />
</customHeaders>
</httpProtocol>
Please note that the Methods are all individually specified, instead of using *. This is because there is a bug occurring when using *.

Related

Axios response get 200 code status, but sometimes data is empty

I'm using a Asp.net Core 2.2 Web API and ReactJS Axios, but sometimes (about 1 in 100 times) the response status is 200 but the data is an empty string.
The server side Controller code is:
[Route("api/[controller]")]
[ApiController]
public class SomeApiController : ControllerBase
{
[HttpPost("GetData")]
public IActionResult GetData([FromBody] int id_search)
{
// *Here I get a list data from back using the id_search*
string json = JsonConvert.SerializeObject(List_data, Formatting.Indented));
// *Here I write the json string in a text file, for debbug the data to send*
return Ok(json);
}
}
So far everything is fine, the json string i wrote in the text file have the data like this:
[
{
"cod_db": 1,
"nom_db": "Nom1"
},
{
"cod_db": 2,
"nom_db": "Nom2"
}
]
The Axios client javascript code is (I'm using axios 0.19.2):
import axios from 'axios';
const clienteAxios = axios.create({
baseURL: 'https://localhost:44364/api/'
}):
export default clienteAxios;
The client side axios method is:
const getData = () => {
const config = {
headers: {
'Content-Type': 'application/json',
// * The next headers I wrote because i think the problem could be CORS too, but I dont know if are necessary *
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials': true ,
'Cache-Control': 'no-cache',
'Access-Control-Allow-Headers': 'Content-type, Accept'
}
}
var id_search = 1;
clienteAxios.post('SomeApi/GetData', id_search, config)
.then(d=>{
console.log(d);
})
.catch(d=>{
console.log("error");
console.log(d);
})
}
And most of the time the response have data, but sometimes (it is difficult to happen), the response data is an empty string, even though the server side effectively sent data (I know because the text file records the data to send) and the .then method was execute with code status 200.
I don't know why this is happening, but I suspect that it could be because of CORS. I have this cors configurations in the Startup.cs archive:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
//CORS ActivaciĆ³n
services.AddCors(
options => options.AddPolicy("EnableCORS",
builder =>
{
builder
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials()
.Build();
})
);
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
//Enable CORS policy "AllowCors"
app.UseCors("EnableCORS");
app.UseHttpsRedirection();
app.UseMvc();
}
Is there something I am doing wrong, or does anyone know why this is happening?
Edit: After a lot of attempts, I finally managed to recreate the error (remember that it is difficult to happen). The Chrome browser developer tools
Console tab shows nothing and the Network tab shows:
Headers:
General:
Request URL: https://localhost:44364/api/Login/GetDataBases
Request Method: POST
Status Code: 200
Remote Address: [::1]:44364
Referrer Policy: no-referrer-when-downgrade
Response Headers:
access-control-allow-credentials: true
access-control-allow-origin: *
content-length: 0
content-type: text/plain; charset=utf-8
date: Fri, 04 Sep 2020 10:16:46 GMT
server: Microsoft-IIS/10.0
status: 200
vary: Origin
x-powered-by: ASP.NET
Request Headers:
:authority: localhost:44364
:method: POST
:path: /api/Login/GetDataBases
:scheme: https
accept: application/json, text/plain, */ *
accept-encoding: gzip, deflate, br
accept-language: es-ES,es;q=0.9
access-control-allow-credentials: true
access-control-allow-headers: Content-type, Accept
access-control-allow-origin: *
cache-control: no-cache
content-length: 1
content-type: application/json
origin: http://localhost:3000
referer: http://localhost:3000/
sec-fetch-dest: empty
sec-fetch-mode: cors
sec-fetch-site: cross-site
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36
Request Payload:
1
No properties
Response:
This request has no response data available.
I suspect that it could be because of CORS.
As you mentioned, the most of requests that ReactJS client send can get expected data, in my view, the issue would not be caused by CORS.
But configuring with both AllowAnyOrigin and AllowCredentials methods is insecure and not recommended, you can specify the allowed origins using WithOrigins method.
sometimes (about 1 in 100 times) the response status is 200 but the data is an empty string.
Based on your code, it seems that you host the app on local, to troubleshoot the issue, you can set break point inside your action method, then debug and trace the id_search and List_data.
Besides, if you host your app on server, to troubleshoot the issue, you can try to write application logs then check application logs to find useful info.
private readonly ILogger _logger;
public SomeApiController(ILogger<SomeApiController> logger)
{
_logger = logger;
}
[HttpPost("GetData")]
public IActionResult GetData([FromBody] int id_search)
{
_logger.LogInformation($"Client passed id_search is '{id_search}'");
//var List_data = YourService.GetDataById(id_search);
if (List_data.Count() < 1)
{
_logger.LogInformation($"Can not get data based on id_search '{id_search}'");
}
string json = JsonConvert.SerializeObject(List_data, Formatting.Indented);
_logger.LogInformation($"Get data based on id_search: {json}");
return Ok(json);
}

Angular 8 fails to read response from a request if there was a large blob in it

I'm developing an API that has an endpoint to update a table with a large blob (15MB or so), this api updates the table then responds with a JSON.
When this endpoint receives a small blob (a few bytes), angular can read the JSON and show the result to the user. If this endpoint receives a large blob, it seems the whole request fails, as firefox shows in the console:
I don't think it is a CORS problem because all other requests I make to this server are OK, even this request is OK if the blob is small enough.
I am usgin Angular 8, Python 3 (with Flask) and Mysql, but I don't think it is a problem with the database or server side configuration (for example max_allowed_packet or innodb_log_file_size for mysql and client_max_body_size for nginx) because the server receives those exact same files in the insert endpoint and everything is fine.
If I save a 15MB file it is successful, but if I try to update that file with another file with the exact same size, then the error appears.
Another thing that makes me believe the problem is not on the server side is that nginx access log shows only successful requests (all responded with code 200)
So I think the problem can only be Angular, but since it works if the blob is small, I have absolutely no idea where the problem could be.
Here is the service that makes the request: (insert works fine with all sizes of blobs, update only with small blobs)
export class documentService {
constructor(private http: HttpClient, private toastr: ToastrService) { }
insert(file:File, tags:Tag[], permitions:User[], extraFields:any, type:string){
const formData = new FormData();
formData.append('tags', JSON.stringify(tags));
formData.append('permitions', JSON.stringify(permitions));
formData.append('binary_data', file);
formData.append('extraFields', JSON.stringify(extraFields))
return this.http.post<Resposta>(SERVER+"/document/"+type, formData, {"reportProgress": true})
}
update(file:File, tags:Tag[], permitions:Usuario[], docId, extraFields:any, type:string){
const formData = new FormData();
formData.append('tags', JSON.stringify(tags));
formData.append('permitions', JSON.stringify(permitions));
formData.append('binary_data', file);
formData.append('extraFields', JSON.stringify(extraFields))
return this.http.put<Resposta>(SERVER+"/document/"+type+"/"+docId, formData, {"reportProgress": true})
}
}
here is the part of the component that uses the above service:
this.docService.update(file, tags, permitions, this.doc.id,this.doc, TYPES.INTERNAL).subscribe( r => {
if(!r.error){
this.setEditMode(false)
this.hide()
}
})
And I also have an interceptor:
export class ApiInterceptor implements HttpInterceptor {
constructor(private toastr: ToastrService, private progress: ShowProgressService) {}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
let newHeaders = { 'Authorization': localStorage.getItem('jwt') || ""}
const cloneReq = req.clone({
setHeaders: newHeaders
});
return next.handle(cloneReq).pipe(
tap((event: any)=>{
if(event.body && event.body.msg && event.body.error!=undefined){
if(event.body.error){
this.toastr.error(event.body.msg)
} else{
this.toastr.success(event.body.msg)
}
}
// shows upload progress
if(event.type === HttpEventType.UploadProgress){
let percentDone = Math.round((100 * event.loaded) / event.total);
this.progress.showUpload(percentDone)
}
if(event.type === HttpEventType.DownloadProgress){
let percentDone = Math.round((100 * event.loaded) / event.total);
this.progress.showDownload(percentDone)
}
})
);
}
}
Edit 1 - OPTIONS Request:
Request:
Host: url
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:72.0) Gecko/20100101 Firefox/72.0
Accept: */*
Accept-Language: pt-BR,pt;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: authorization
Referer: http://url/dashboard
Origin: http://url
DNT: 1
Connection: keep-alive
Response:
HTTP/1.1 200 OK
Server: nginx/1.10.3
Date: Thu, 13 Feb 2020 20:30:39 GMT
Content-Type: text/html; charset=utf-8
Content-Length: 0
Connection: keep-alive
Allow: GET, HEAD, PUT, OPTIONS, DELETE
Access-Control-Allow-Origin: http://url
Vary: Origin
Access-Control-Allow-Headers: authorization
Access-Control-Allow-Methods: DELETE, GET, HEAD, OPTIONS, PATCH, POST, PUT
Based on your OPTIONS response added, it looks like you're not correctly setting the Access-Control-Allow-Origin header in the server's response to the CORS OPTIONS request.
Try setting Access-Control-Allow-Origin: * in your server's response to see if CORS is the issue, then replace the * wildcard with the appropriate origin you'll be using to prevent potentially malicious cross origin requests

AngularJS Call WebMethod an return a JSON string [duplicate]

Why does this simple web service refuse to return JSON to the client?
Here is my client code:
var params = { };
$.ajax({
url: "/Services/SessionServices.asmx/HelloWorld",
type: "POST",
contentType: "application/json; charset=utf-8",
dataType: "json",
timeout: 10000,
data: JSON.stringify(params),
success: function (response) {
console.log(response);
}
});
And the service:
namespace myproject.frontend.Services
{
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
[ScriptService]
public class SessionServices : System.Web.Services.WebService
{
[WebMethod]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public string HelloWorld()
{
return "Hello World";
}
}
}
web.config:
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
</configuration>
And the response:
<?xml version="1.0" encoding="utf-8"?>
<string xmlns="http://tempuri.org/">Hello World</string>
No matter what I do, the response always comes back as XML. How do I get the web service to return Json?
EDIT:
Here is the Fiddler HTTP trace:
REQUEST
-------
POST http://myproject.local/Services/SessionServices.asmx/HelloWorld HTTP/1.1
Host: myproject.local
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:13.0) Gecko/20100101 Firefox/13.0.1
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: en-gb,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Type: application/json; charset=utf-8
X-Requested-With: XMLHttpRequest
Referer: http://myproject.local/Pages/Test.aspx
Content-Length: 2
Cookie: ASP.NET_SessionId=5tvpx1ph1uiie2o1c5wzx0bz
Pragma: no-cache
Cache-Control: no-cache
{}
RESPONSE
-------
HTTP/1.1 200 OK
Cache-Control: private, max-age=0
Content-Type: text/xml; charset=utf-8
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Date: Tue, 19 Jun 2012 16:33:40 GMT
Content-Length: 96
<?xml version="1.0" encoding="utf-8"?>
<string xmlns="http://tempuri.org/">Hello World</string>
I have lost count of how many articles I have read now trying to fix this. The instructions are either incomplete or do not solve my issue for some reason.
Some of the more relevant ones include (all without success):
ASP.NET web service erroneously returns XML instead of JSON
asmx web service returning xml instead of json in .net 4.0
http://williamsportwebdeveloper.com/cgi/wp/?p=494
http://encosia.com/using-jquery-to-consume-aspnet-json-web-services/
http://forums.asp.net/t/1054378.aspx
http://jqueryplugins.info/2012/02/asp-net-web-service-returning-xml-instead-of-json/
Plus several other general articles.
Finally figured it out.
The app code is correct as posted. The problem is with the configuration. The correct web.config is:
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0" />
</system.web>
<system.webServer>
<handlers>
<add name="ScriptHandlerFactory"
verb="*" path="*.asmx"
type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
resourceType="Unspecified" />
</handlers>
</system.webServer>
</configuration>
According to the docs, registering the handler should be unnecessary from .NET 4 upwards as it has been moved to the machine.config. For whatever reason, this isn't working for me. But adding the registration to the web.config for my app resolved the problem.
A lot of the articles on this problem instruct to add the handler to the <system.web> section. This does NOT work and causes a whole load of other problems. I tried adding the handler to both sections and this generates a set of other migration errors which completely misdirected my troubleshooting.
In case it helps anyone else, if I had ther same problem again, here is the checklist I would review:
Did you specify type: "POST" in the ajax request?
Did you specify contentType: "application/json; charset=utf-8" in the ajax request?
Did you specify dataType: "json"in the ajax request?
Does your .asmx web service include the [ScriptService] attribute?
Does your web method include the [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
attribute? (My code works even without this attribute, but a lot of articles say that it is required)
Have you added the ScriptHandlerFactory to the web.config file in <system.webServer><handlers>?
Have you removed all handlers from the the web.config file in in <system.web><httpHandlers>?
Hope this helps anyone with the same problem. and thanks to posters for suggestions.
No success with above solution, here how I resolved it.
put this line into your webservice and rather return type just write the string in response context
this.Context.Response.ContentType = "application/json; charset=utf-8";
this.Context.Response.Write(serial.Serialize(city));
If you want to stay remain with Framework 3.5, you need to make change in code as follows.
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
[ScriptService]
public class WebService : System.Web.Services.WebService
{
public WebService()
{
}
[WebMethod]
public void HelloWorld() // It's IMP to keep return type void.
{
string strResult = "Hello World";
object objResultD = new { d = strResult }; // To make result similarly like ASP.Net Web Service in JSON form. You can skip if it's not needed in this form.
System.Web.Script.Serialization.JavaScriptSerializer ser = new System.Web.Script.Serialization.JavaScriptSerializer();
string strResponse = ser.Serialize(objResultD);
string strCallback = Context.Request.QueryString["callback"]; // Get callback method name. e.g. jQuery17019982320107502116_1378635607531
strResponse = strCallback + "(" + strResponse + ")"; // e.g. jQuery17019982320107502116_1378635607531(....)
Context.Response.Clear();
Context.Response.ContentType = "application/json";
Context.Response.AddHeader("content-length", strResponse.Length.ToString());
Context.Response.Flush();
Context.Response.Write(strResponse);
}
}
There is much easier way to return a pure string from web service. I call it CROW function (makes it easy to remember).
[WebMethod]
public void Test()
{
Context.Response.Output.Write("and that's how it's done");
}
As you can see, return type is "void", but CROW function will still return the value you want.
I have a .asmx web service (.NET 4.0) with a method that returns a string. The string is a serialized List like you see in many of the examples. This will return json that is not wrapped in XML. No changes to web.config or need for 3rd party DLLs.
var tmsd = new List<TmsData>();
foreach (DataRow dr in dt.Rows)
{
m_firstname = dr["FirstName"].ToString();
m_lastname = dr["LastName"].ToString();
tmsd.Add(new TmsData() { FirstName = m_firstname, LastName = m_lastname} );
}
var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
string m_json = serializer.Serialize(tmsd);
return m_json;
The client part that uses the service looks like this:
$.ajax({
type: 'POST',
contentType: "application/json; charset=utf-8",
dataType: 'json',
url: 'http://localhost:54253/TmsWebService.asmx/GetTombstoneDataJson',
data: "{'ObjectNumber':'105.1996'}",
success: function (data) {
alert(data.d);
},
error: function (a) {
alert(a.responseText);
}
});
Hope this helps, it appears that you still have to send some JSON object in the request, even if the Method you are calling has no parameters.
var params = {};
return $http({
method: 'POST',
async: false,
url: 'service.asmx/ParameterlessMethod',
data: JSON.stringify(params),
contentType: 'application/json; charset=utf-8',
dataType: 'json'
}).then(function (response) {
var robj = JSON.parse(response.data.d);
return robj;
});
For me it works with this code I got from this post:
How can I return json from my WCF rest service (.NET 4), using Json.Net, without it being a string, wrapped in quotes?
[WebInvoke(UriTemplate = "HelloWorld", Method = "GET"), OperationContract]
public Message HelloWorld()
{
string jsonResponse = //Get JSON string here
return WebOperationContext.Current.CreateTextResponse(jsonResponse, "application/json; charset=utf-8", Encoding.UTF8);
}
I have tried all of the above steps ( even the answer), but i was not successful, my system configuration is Windows Server 2012 R2, IIS 8. The following step solved my problem.
Changed the app pool, that has managed pipeline = classic.
I know that is really old question but i came to same problem today and I've been searching everywhere to find the answer but with no result. After long research I have found the way to make this work. To return JSON from service you have provide data in request in the correct format, use JSON.stringify() to parse the data before request and don't forget about contentType: "application/json; charset=utf-8", using this should provide expected result.
response = await client.GetAsync(RequestUrl, HttpCompletionOption.ResponseContentRead);
if (response.IsSuccessStatusCode)
{
_data = await response.Content.ReadAsStringAsync();
try
{
XmlDocument _doc = new XmlDocument();
_doc.LoadXml(_data);
return Request.CreateResponse(HttpStatusCode.OK, JObject.Parse(_doc.InnerText));
}
catch (Exception jex)
{
return Request.CreateResponse(HttpStatusCode.BadRequest, jex.Message);
}
}
else
return Task.FromResult<HttpResponseMessage>(Request.CreateResponse(HttpStatusCode.NotFound)).Result;

OPTIONS (failed) only on Chrome and Firefox

I make a POST request and the request just sits, pending until it eventually fails. I've monitored the nginx logs and the node server logs and the request doesn't even register. This works for anyone else that I've had test it except one other colleague. If I use the edge browser or a different computer it works fine.
I have attempted to make POST requests to other (custom) servers and it hangs on options there as well. I have also made the POST request with jQuery and it fails the same way.
It's maybe worth noting that I am using the withCredentials flag.
Headers:
Provisional headers are shown
Access-Control-Request-Headers:content-type
Access-Control-Request-Method:GET
Origin:http://localhost:8080
Referer:http://localhost:8080/<path>
User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.84 Safari/537.36
The request:
public login(user) {
const endpoint = `http://<url>`;
let headers = new Headers();
headers.append('Content-type', 'application/json');
return this.http
.post(endpoint, JSON.stringify(user), {
headers: headers,
});
}
I subscribe to the call in my component:
this._accountService.login(this.user)
.subscribe(res => {
console.log("logged in!");
if (res.json().status === "success") {
window.location.href = `/home/${this.org}/${this.product}`;
}
else {
// What other options are there?
console.log("Do something else maybe?");
}
},
err => {
this.invalidLogin = true;
console.log("Ye shall not pass!");
});
Successful user's headers
Accept:*/*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:en-US,en;q=0.8
Access-Control-Request-Headers:content-type
Access-Control-Request-Method:POST
Connection:keep-alive
Host:<url>
Origin:<url>
Referer:<url>
User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.33 Safari/537.36
From chrome://net-internals/#events
t=61869793 [st= 0] +REQUEST_ALIVE [dt=60162]
--> has_upload = false
--> is_pending = true
--> load_flags = 34624 (DO_NOT_SAVE_COOKIES | DO_NOT_SEND_AUTH_DATA | DO_NOT_SEND_COOKIES | MAYBE_USER_GESTURE | VERIFY_EV_CERT)
--> load_state = 14 (WAITING_FOR_RESPONSE)
--> method = "OPTIONS"
--> net_error = -1 (ERR_IO_PENDING)
--> status = "IO_PENDING"
--> url = "<url>"
t=61929955 [st=60162] -HTTP_STREAM_PARSER_READ_HEADERS
--> net_error = -324 (ERR_EMPTY_RESPONSE)
t=61929955 [st=60162] -HTTP_TRANSACTION_READ_HEADERS
--> net_error = -324 (ERR_EMPTY_RESPONSE)
t=61929955 [st=60162] -URL_REQUEST_START_JOB
--> net_error = -324 (ERR_EMPTY_RESPONSE)
t=61929955 [st=60162] URL_REQUEST_DELEGATE [dt=0]
t=61929955 [st=60162] -REQUEST_ALIVE
--> net_error = -324 (ERR_EMPTY_RESPONSE)
I'm really guessing this is related to something that is cached in my browser(s) but I really cannot find what. I've cleared all cookies and anything that could be stored. Where else can I check to clear things? This is clearly something local to my computer/browser (and one other unfortunate person).
Please try to subscribe() to the observable.
return this.http
.post(endpoint, JSON.stringify(user), {
headers: headers,
}).subscribe(() => console.log("POST done!"));
Have you tried setting the 'Cache-Control' in your headers? I think in jQuery you can simply set
$.ajax({
cache: false
});
or adding a header with a regular ajax request
request.setRequestHeader("Cache-Control", "no-cache");
Why don't you just prevent getting into OPTIONS request loop . It really drives you crazy at times . Other browsers do not trigger OPTIONS request but chrome and firefox does to ensure CORS . I have successfully used this library named as xdomain from github , and it really works !! Their github introduction page introduce xdomain as a CORS alternative . And most importantly i used it in JQuery , but it also does support Angular's http service . Have a look at it . It may help you for good :) . Here's the link to library Xdomain CORS Alternative
There are issues with CORS and using localhost as the domain (which you have listed in the ORIGIN headers). Typically CORS / OPTIONS requests don't work properly when localhost is involved for certain security reasons, but hanging isn't normally what happens so this might not be the correct answer but its worth a shot!
Try adding a new host to your local machine and removing localhost from the equation. Just throwing this idea out there and hope that it might help you out!
As per comment below
Your server appears to allow the connection, but it does not appear to send a response. Are you able to post the headers from a successful OPTIONS request to prove that the server is actually able to handle these requests.

How to disable 'withcredentials' in HTTP header with node.js and Request package?

Using node.js and the Request package from the browser (via browserify), I am using CORS to do a HTTP GET request on a separate domain.
On the server, when I set 'Access-Control-Allow-Origin' to the wildcard '*', I get the following error on the client:
XMLHttpRequest cannot load .... A wildcard '*' cannot be used in the
'Access-Control-Allow-Origin' header when the credentials flag is
true. Origin '...' is therefore not allowed access.
The HTTP request header looks like this:
Accept:*/*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8,ja;q=0.6
Access-Control-Request-Headers:withcredentials
Access-Control-Request-Method:GET
Cache-Control:no-cache
Connection:keep-alive
Host:localhost:3000
Origin:http://localhost:9966
Pragma:no-cache
Referer:http://localhost:9966/
User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36
So clearly the problem is Access-Control-Request-Headers:withcredentials in the header, right?
To be able to remove this, I need to set the 'withcredentials' property of the 'XMLHttpRequest' object to 'false'. However, I cannot figure out where node.js or the Request package are creating the 'XMLHttpRequest' object, and how I can even access this.
Thanks.
After some investigation, I discovered that the withCredentials setting can be passed in via the options parameter object:
var req = http.request({
withCredentials: false
}, function(res) {
//...
});
req.end();
If undefined, the default setting is true.
Reference from the http-browserify/lib/request.js source:
if (typeof params.withCredentials === 'undefined') {
params.withCredentials = true;
}
try { xhr.withCredentials = params.withCredentials }
catch (e) {}

Categories

Resources