Axios post request failing due to CORS but the same request using ajax is getting no issues - vue.js

I am getting following error wile doing axios post request.
But when I use ajax request there is no issue:
request has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Ajax Request:
Axios request:
let payload = {
type: ["a", "b"],
category: ["a", "b"],
category: ["a", "b"],
accountNumber: "123"
};
var apiURL = this.$apiBaseURL + "/Product/ProductDetails";
$.ajax({
url: apiURL,
type: "POST",
data: { payload },
xhrFields: {
withCredentials: true
},
success: function (result) {
console.log(JSON.stringify(result));
}
});
this.$http.post(apiURL,payload,{withCredentials: true})
**UPDATE 1 **
I am still facing the same issue. Here I will share the request header in both ajax and axios request
AJAX Working code and request header :
{
var apiURL = this.$apiBaseURL + "/Request/MediaUpload";
$.ajax({
method: 'post',
processData: false,
contentType: false,
cache: false,
data: fileformData,
enctype: 'multipart/form-data',
url: apiURL,
xhrFields: {
withCredentials: true
}
});
}
Request header:
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
Content-Length: 7610
Content-Type: multipart/form-data; boundary=----
WebKitFormBoundaryAjc8HwVPaRtQ5Iby
Host: localhost:62148
Origin: http://localhost:8989
Referer: http://localhost:8989/
Sec-Fetch-Mode: cors
Sec-Fetch-Site: same-site
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
(KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36
AXIOS failing code and header
var apiURL = this.$apiBaseURL + "/Request/MediaUpload";
var self=this;
let config={
headers:{
'Content-Type': 'multipart/form-data'
}
}
this.$http.post(apiURL, { withCredentials: true },fileformData,
config)
Request Headers:
Provisional headers are shown
Accept: application/json, text/plain, */*
Content-Type: application/json;charset=UTF-8
Referer: http://localhost:8989/
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36
Here is my web api config where I have enabled cors
string origin = "http://localhost:8989";
EnableCorsAttribute cors = new EnableCorsAttribute(origin, "*", "*", "*");
cors.SupportsCredentials = true;
config.EnableCors(cors);
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
**UPDATE 2 **
The CORS configuration at server side is done correctly thats why I am able to make the call successfully via AJAX.
Is this a known AXIOS issue which occurs only when we enable the windows authentication?

This issue arises because jQuery sends the request as application/x-www-form-urlencoded by default and does not send preflight request whereas axios sends as application/json and sends a preflight request i.e. OPTIONS before sending actual request.
One way it could work is by setting Content-type header to 'Content-Type': 'application/x-www-form-urlencoded' in axios.
You will have to change the settings on server side to get around this issue.

Add this in your web.config file:
<system.webServer>
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="OPTIONSVerbHandler" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
Using default ajax won't send any OPTIONS request, but using axios does. This will enable accepting OPTIONS requests.

Related

CORS with Flask, axios and https not working (response header sends origin as http instead of https)

My frontend (Expo Go web) is running at http://localhost:19006/ but when it receives a response from the backend, it somehow believes it runs under https://localhost:19006/
Also, the iOS version of Expo Go logs the following error:
LOG [AxiosError: Network Error]
I'm using Flask in the backend with CORS set as follows:
app = Flask(__name__)
app.config['DEBUG'] = True
app.config['CORS_HEADERS'] = 'Content-Type'
app.config['SECRET_KEY'] = os.environ.get("SECRET_KEY", 'xxx')
cors = CORS(app, resources={r"/*": {"origins": "*", "allow_headers": "*", "expose_headers": "*", "Access-Control-Allow-Origin": "*"}})
and a simple return function:
#app.route("/matches", methods=["GET"])
def getMatches():
print('request for matches')
response = matches.getMatches()
return response
if __name__ == '__main__':
app.run(ssl_context=('certs/cert.pem', 'certs/key.pem'))
My frontend part is using react native with Expo Go. The query to the backend is done this way:
export default function App() {
const axiosApiCall = () => {
const config = {
headers:{
'origin': 'https://localhost:19006' #<- Here also tried http but no change
}
};
axios
.get("https://127.0.0.1:5000/matches", config)
.then((response) => {
setState({quote : 'yes'});
console.log(response.data);
})
.catch((error) => {
console.log(error);
})
}
The backend works properly fine as I can see in Postman. The result is technically showing up in the response of the web-version of Expo Go, however, it appears that there's an issue with CORS:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://127.0.0.1:5000/matches. (Reason: CORS header ‘Access-Control-Allow-Origin’ does not match ‘https://localhost:19006’).
And here's the response header:
HTTP/1.1 200 OK
Server: Werkzeug/2.2.2 Python/3.9.16
Date: Thu, 05 Jan 2023 10:16:42 GMT
Content-Type: application/json
Content-Length: 274552
Access-Control-Allow-Origin: http://localhost:19006
Access-Control-Expose-Headers: *
Vary: Origin
Connection: close
GET /matches HTTP/1.1
Host: 127.0.0.1:5000
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:108.0) Gecko/20100101 Firefox/108.0
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Origin: http://localhost:19006
DNT: 1
Connection: keep-alive
Referer: http://localhost:19006/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
Sec-GPC: 1
Anyone any idea? Thanks!!!
Hardcoding the CORS origins: no change
Changing the query from axios to async fetch calls: no change
Including/modifying the header in the axios config: no change
Other browsers: no change
Deactivating SSL in the backend: caused other problems related to react native

Axios Post return 405 Method Not Allowed on Vue.js

I'm trying to made a POST request on a NET CORE 5 service (hosted on IIS 10) from a Vue.js app with axios.
When I test the service with POSTMAN it's working perfectly but with Axios I'm always getting a 405 from the server.
Analyzing the requests with fiddler are looking very different. IN the axios request the content-type header is missing and the method is OPTIONS instead of POST.
This is the POSTMAN request:
POST https://localhost/apiluxor/api/SignIn HTTP/1.1
Content-Type: application/json
User-Agent: PostmanRuntime/7.28.4
Accept: */*
Postman-Token: acfed43c-731b-437b-a88a-e640e8216032
Host: localhost
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Content-Length: 55
{
"username":"user",
"password":"testpw"
}
And this is the axios request:
OPTIONS https://localhost/apiluxor/api/SignIn HTTP/1.1
Host: localhost
Connection: keep-alive
Accept: */*
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type
Origin: http://172.16.1.110:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.54 Safari/537.36
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
Sec-Fetch-Dest: empty
Referer: http://172.16.1.110:8080/
Accept-Encoding: gzip, deflate, br
Accept-Language: it-IT,it;q=0.9,en-US;q=0.8,en;q=0.7
In my Vue.js module I've tried to force the settings of the 'content-type' in the main config and in the post request with no results.
import { App } from "vue";
import axios from "axios";
import VueAxios from "vue-axios";
import JwtService from "#/core/services/JwtService";
import { AxiosResponse, AxiosRequestConfig } from "axios";
class ApiService {
public static vueInstance: App;
public static init(app: App<Element>) {
ApiService.vueInstance = app;
ApiService.vueInstance.use(VueAxios, axios);
ApiService.vueInstance.axios.defaults.baseURL =
"https://localhost/apiluxor/api";
ApiService.vueInstance.axios.defaults.headers.post["Content-Type"] =
"application/json";
}
public static setHeader(): void {
ApiService.vueInstance.axios.defaults.headers.common[
"Authorization"
] = `Bearer ${JwtService.getToken()}`;
}
public static post(
resource: string,
params: AxiosRequestConfig
): Promise<AxiosResponse> {
return ApiService.vueInstance.axios.post(resource, params, {
headers: { "content-type": "application/json" },
});
}
export default ApiService;
I'm very new to Vue.js so maybe I'm missing something.
The problem is that axios made a CORS request before the POST, and the NET Core API should be configured to accept CORS request.
I've found an article (here) that saying the problem for this cases is that IIS does not accept CORS request and the CORS module should be installed .
I've tried this change but the result was the I was receving an HTTP/1.1 204 No Content instead of a 403.
In my case the problem was the API service itself.
The CORS should be enabled in the API Service.
In NET CORE 5 for a basic configuration it's enough to add the CORS services in Startup
services.AddCors();
and configure it
app.UseCors(builder =>
{
builder
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
});
With these changes the service works perfectly for any vue.js requests coming from axios.
To send the data as JSON in the body of the post request, just add a parameter "data" to the axios options. Axios will automatically set the content-tpe to the proper value for you.
// Simple example
axios.post(myUrl, {
data: {
"username":"user",
"password":"testpw"
}
});
This should have the expected outcome :)

Outlook Add-in REST call error

I'm trying to mark (flag) a message using the Outlook rest API, but I keep getting error messages. I've tried with different rest URLs but it doesn't help - the errors just varies.
Important values in the manifest for allowing this I believe are:
<Requirements>
<Sets>
<Set Name="Mailbox" MinVersion="1.1" />
</Sets>
</Requirements>
...
<Permissions>ReadWriteItem</Permissions>
<Rule xsi:type="RuleCollection" Mode="Or">
<Rule xsi:type="ItemIs" ItemType="Message" FormType="Read" />
</Rule>
...
<VersionOverrides xmlns="http://schemas.microsoft.com/office/mailappversionoverrides" xsi:type="VersionOverridesV1_0">
<Requirements>
<bt:Sets DefaultMinVersion="1.3">
<bt:Set Name="Mailbox" />
</bt:Sets>
</Requirements>
Here is the part I'm trying to do that causes error:
Office.context.mailbox.getCallbackTokenAsync({ isRest: true }, function (result)
{
if (result.status === "succeeded")
{
var accessToken = result.value;
var itemId = getItemRestId();
var restUrl = Office.context.mailbox.restUrl + "/api/v2.0/messages/" + itemId;
var request = {
url: restUrl,
type: "PATCH",
dataType: 'json',
data: { "Flag": { "FlagStatus": "Flagged" } },
headers: {
"Authorization": "Bearer " + accessToken,
"Conntent-Type": "application/json"
}
};
$.ajax(request)
.done(function (item)
{
// dome something
})
.fail(function (error)
{
// handle error
});
}
else
{
// handle error
}
});
function getItemRestId()
{
if (Office.context.mailbox.diagnostics.hostName === 'OutlookIOS')
{
return Office.context.mailbox.item.itemId;
}
else
{
return Office.context.mailbox.convertToRestId(
Office.context.mailbox.item.itemId,
Office.MailboxEnums.RestVersion.Beta
);
}
}
This code above will result in the error:
{"readyState":4,"responseText":"","status":404,"statusText":"Not Found"}
If I try to JSON.stringify() the data attribute of the request I get:
{"readyState":4,"responseText":"","status":404,"statusText":"Not Found"}
If I change the rest URL to (seen in older samples):
'https://outlook.office.com/api/beta/me/messages/'+ itemId;
And the headers attribute of the request to (seen in older samples):
headers: {
'Authorization': 'Bearer ' + accessToken,
'Content-Type': 'application/json'
}
Then I get the following error instead:
{
"readyState": 4,
"responseText": "{\"error\":{\"code\":\"ErrorAccessDenied\",\"message\":\"The api you are trying to access does not support item scoped OAuth.\"}}",
"responseJSON": {
"error": {
"code": "ErrorAccessDenied",
"message": "The api you are trying to access does not support item scoped OAuth."
}
},
"status": 403,
"statusText": "Forbidden"
}
Can anyone see what I'm doing wrong or missing here?
I'm debugging in Outlook 2016 and the account is Office 365.
UPDATE: Fiddler outputs
Here is the request my own sample sends (results in 403 Forbidden)
Exact error: {"error":{"code":"ErrorAccessDenied","message":"The api you are trying to access does not support item scoped OAuth."}}
PATCH https://outlook.office.com/api/beta/me/messages/AAMkAGNmMDllMTVhLTI3ZDctNDYxZS05ZWM5LTA3ZWQzMzYyNDBiOABGAAAAAAD6OQOAoKyKT6R02yYFe0bIBwD5fUzv7OgQQYAILztCFSSWAALg591rAAC382lxTQ2HQpUKZsAGTeWVAARPu37CAAA= HTTP/1.1
Content-Type: application/json
Accept: application/json, text/javascript, */*; q=0.01
Authorization: Bearer <long token code removed...>
Referer: https://localhost:44394/MessageRead.html?_host_Info=Outlook$Win32$16.02$da-DK
Accept-Language: da-DK
Origin: https://localhost:44394
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko
Host: outlook.office.com
Content-Length: 33
Connection: Keep-Alive
Cache-Control: no-cache
{"Flag":{"FlagStatus":"Flagged"}}
Here is the request the demo project sends (results in 200 OK)
PATCH https://outlook.office.com/api/beta/me/messages/AAMkAGNmMDllMTVhLTI3ZDctNDYxZS05ZWM5LTA3ZWQzMzYyNDBiOABGAAAAAAD6OQOAoKyKT6R02yYFe0bIBwD5fUzv7OgQQYAILztCFSSWAALg591rAAC382lxTQ2HQpUKZsAGTeWVAARPu37CAAA= HTTP/1.1
Content-Type: application/json
Accept: application/json, text/javascript, */*; q=0.01
Authorization: Bearer <long token code removed...>
Referer: https://<company.domain.com>:1443/outlookaddindemo/RestCaller/RestCaller.html?_host_Info=Outlook$Win32$16.02$da-DK
Accept-Language: da-DK
Origin: https://<company.domain.com>:1443
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko
Host: outlook.office.com
Content-Length: 47
Connection: Keep-Alive
Cache-Control: no-cache
{
"Flag": {
"FlagStatus": "Flagged"
}
}
The only difference I can see is that the 2nd request payload seems formatted for reading while data wise being identical to the previous one.
I can't seem to find the problem here - I even made sure that both projects use the same version of JQuery.
If you need write access to the item via REST, you need to specify ReadWriteMailbox in the Permissions element in your manifest. Despite it's name, ReadWriteItem doesn't give you a token with the proper scope. Any permission level other than ReadWriteMailbox gives an item-scoped token, and as the error says, the operation you're trying to do doesn't support item-scoped OAuth.
See https://learn.microsoft.com/en-us/outlook/add-ins/use-rest-api for details, but here's the relevant bit:
Add-in permissions and token scope
It is important to consider what level of access your add-in will need via the REST APIs. In most cases, the token returned by getCallbackTokenAsync will provide read-only access to the current item only. This is true even if your add-in specifies the ReadWriteItem permission level in its manifest.
If your add-in will require write access to the current item or other items in the user's mailbox, your add-in must specify the ReadWriteMailbox permission level in its manifest. In this case, the token returned will contain read/write access to the user's messages, events, and contacts.

ASP.NET 5: Upload file through WebApi

I'm sending file to WebApi using Jquery.ajax
I have an ASP.NET method that receives file
[HttpPost]
[ActionName("import")]
public int Import([FromBody]IFormFile upload)
Inside Import method a can save Request.Body and it looks correct:
------WebKitFormBoundaryZLHvtGDqa5zp0JHB Content-Disposition: form-data; name="upload"; filename="test.b3d"
Content-Type: application/octet-stream
Hello world content!
but upload variable is always null! What should I fix to have file contents inside "upload" variable?
PS: I send file to server using this code:
// Create a formdata object and add the files
var data = new FormData();
data.append("upload", file.files[0]);
jQuery.ajax({
type: "POST",
url: "/api/designer/import",
contentType: "application/json",
dataType: 'json',
processData: false,
data: data
})
The request headers in Chrome:
Accept:application/json, text/javascript, */*; q=0.01
Accept-Encoding:gzip, deflate
Accept-Language:en-US,en;q=0.8,ru;q=0.6
Connection:keep-alive
Content-Length:28855
Content-Type:application/x-www-form-urlencoded
Host:localhost:64867
Origin:http://localhost:64867
Referer:http://localhost:64867/
User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36
X-Requested-With:XMLHttpRequest
Remove the FromBody attribute decorated on the parameter to enable binding data of application/x-www-form-urlencoded format.
This is a change from how existing Web API works. You can use FromBody in cases other than application/x-www-form-urlencoded, like application/json, application/xml etc.

ajax post works vs. angularjs $http does not work w/ ASP.NET MVC 4

I have two projects client side and server side.
Client side project is pure htmljs. Server side is ASP.NET MVC 4 and Web Api.
Because there are two projects I need to enable CROS functionality.
I added into server's webconfig:
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
</customHeaders>
</httpProtocol>
</system.webServer>
Ajax Post version which is working:
$.post(url, appContext).done(
function(data, textStatus, jqXHR) {
successFn(data, textStatus);
})
.fail(
function(jqXHR, textStatus, err) {
errorFn(err, textStatus);
});
angular $http Post version which is NOT working:
$http({
url: url,
method: 'POST',
params: { appContext: appContext },
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
/*'Accept': 'text/json'*/}
}).success(successFn).error(errorFn);
When I use $http I am getting two errors:
OPTIONS url 405 (Method Not Allowed)
POST url 500 (Internal Server Error)
ASP.NET MVC method is
[System.Web.Http.HttpPost]
public List<Module> GetModules([FromBody]SessionContext appContext)
{
return CreateModules();
}
EDIT:
Angular model's configuration:
var emsApp = angular.module('EmsWeb', ['ui.bootstrap']);
emsApp.config(['$routeProvider', '$httpProvider', function($routeProvider, $httpProvider) {
$httpProvider.defaults.useXDomain = true;
delete $httpProvider.defaults.headers.common['X-Requested-With'];
}]);
Headers of OPTIONS request that I see in browser:
Request URL:http://localhost/EmsWeb/api/ModuleApi/GetModules?appContext=%7B%22globalDate%22%3A%22Mon%2C%2008%20Jul%202013%2013%3A09%3A35%20GMT%22%2C%22userToken%22%3A%22AlexToken%22%7D
Request Method:OPTIONS
Status Code:405 Method Not Allowed
Request Headers
Accept:*/*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Access-Control-Request-Headers:accept, origin, content-type
Access-Control-Request-Method:POST
Connection:keep-alive
DNT:1
Host:localhost
Origin:http://localhost:50463
Referer:http://localhost:50463/index.html
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.116 Safari/537.36
Query String Parametersview sourceview URL encoded
appContext:{"globalDate":"Mon, 08 Jul 2013 13:09:35 GMT","userToken":"AlexToken"}
Response Headers
Access-Control-Allow-Headers:Content-Type
Access-Control-Allow-Origin:*
Cache-Control:no-cache
Content-Length:76
Content-Type:application/json; charset=utf-8
Date:Mon, 08 Jul 2013 13:09:35 GMT
Expires:-1
Pragma:no-cache
Server:Microsoft-IIS/7.5
X-AspNet-Version:4.0.30319
X-Powered-By:ASP.NET
Any ideas why angular way does not work are appreciated?
Update the issue as it turns out to be quite silly:
because I used params and instead of data in:
$http({
url: url,
method: 'POST',
params: { appContext: appContext },
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
/*'Accept': 'text/json'*/}
}).success(successFn).error(errorFn);
angular converted to GetRequest. No need for ContentType either.
so actual code is
$http({method: 'POST',
url: url,
data: appCtx,
}).success(successFn).error(errorFn);
so ALMOST resolved, I see that angular still issues OPTIONS request that fails but post request goes through...
so any ideas on that one are appreciated
My issue were due to two reasons:
I used params and instead of data in
$http({
url: url,
method: 'POST',
params: { appContext: appContext },
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
/*'Accept': 'text/json'*/}
}).success(successFn).error(errorFn);
angular converted to GetRequest. No need for ContentType either. so actual code is
$http({method: 'POST',
url: url,
data: appCtx,
}).success(successFn).error(errorFn);
on the server side
I needed something handling OPTIONS request. One way is to decorate method w/ [System.Web.Http.AcceptVerbs("OPTIONS")], which I do not think the best way.
Another way is to add Custom Message Handler.
I am still researching it...
If your ajax is working then it looks like the angular side of things isn't configured. Add this before you use $http (in your controller setup).
$http.defaults.useXDomain = true;
See this guys jsfiddle for a working example: http://jsfiddle.net/ricardohbin/E3YEt/
EDIT: Further to your comment and edit to the question, this post might help you: http://www.codeguru.com/csharp/.net/net_asp/using-cross-origin-resource-sharing-cors-in-asp.net-web-api.html
-Be sure about the syntax of get and Post and the way of sending parameters
-Check the expected Parameter that you expect at the destination action or method and be sure that the sending one and receiving one are the same.