extjs file uploads through form submit for cross domain - javascript

I would like to upload files to cross domain server from extjs using form.submit() method. When i call form.submit(), request is going to my restful web service and file is getting uploaded successfully. But the response is blocked at the browser with message: Blocked a frame with origi…host:1841" from accessing a cross-origin frame.
From older posts and form submit code, i found that doSubmit() is sending the Ajax request with out cors:true statement due to which cross domain response is blocked.
I thought of sending normal Ajax request but dont know how the file data can be read and send to server through ajax request.
Is there anyway in php to send the file data to server as form.doSubmit()does? Can someone help me on this problem?
Thanks.
Solution is: What does document.domain = document.domain do? and http://codeengine.org/extjs-fileuplaod-cross-origin-frame/

In case someone faces the same issue... Extjs 6.6
Objective: Using fileUpload and form.submit with CORS.
Issue: ExtJS form.submit failed due to “accessing a cross-origin frame -> The file gets successfully uploaded however it ALWAYS returns FAILURE on form.submit Reason..."Blocked a frame with origin "http://localhost:57007" from accessing a cross-origin frame."
Solution: Don't use form.submit, use fetch instead.
View
{
xtype: 'form',
reference: 'fileForm',
items: [
{
xtype: 'fileuploadfield',
buttonOnly: true,
name: 'file',
buttonConfig: {
text: 'Attach',
iconCls: 'x-fa fa-plus green',
ui: 'default-toolbar-small'
},
width: 80,
listeners: {
change: 'onAttachFile'
}
}
]
},
View Controller
/**
*
*/
onAttachFile: function (cmp, newValue) {
const self = this;
const fileForm = self.lookupReference('fileForm');
if (Ext.isEmpty(newValue) === false && fileForm.isValid()) {
const file = cmp.fileInputEl.dom.files[0];
const fileSizeInMB = parseFloat((file.size / (1024*1024)).toFixed(2));
// Validating file size
if (fileSizeInMB > 4)
alert('File size exceeds the allowable limit: 4MB');
else {
const url = '' // URL goes here
const headers = {} // Any special headers that you may need, ie auth headers
const formData = new FormData();
formData.append('file', file);
fetch(url, {
method: 'POST',
headers,
credentials: 'include',
body: formData
})
.then(response => {
response.json().then(json => {
if (response.ok) {
console.log(json);
}
else {
console.error(json);
}
});
})
.catch((error) => {
console.error(error);
});
}
}
},
Related Posts:
cross origin problems with extjs 6.01
extjs form.submit failed due to "accessing a cross-origin frame"
extjs file uploads through form submit for cross domain
ExtJS 6.6.0 Enable CORS in form submit
https://forum.sencha.com/forum/showthread.php?368824-extjs-form-submit-failed-due-to-%E2%80%9Caccessing-a-cross-origin-frame%E2%80%9D
https://forum.sencha.com/forum/showthread.php?298504-Extjs-5-Fileupload-submit-error
https://forum.sencha.com/forum/showthread.php?294852
https://forum.sencha.com/forum/showthread.php?343448-Cross-origin-file-upload

Ajax call does not work with downloading and i presume with uploading files.
Have you tried to set this before doSubmit:
Ext.Ajax.cors = true;
Ext.Ajax.useDefaultXhrHeader = false;

Solution is: What does document.domain = document.domain do? and http://codeengine.org/extjs-fileuplaod-cross-origin-frame/

Related

CORS No 'Access-Control-Allow-Origin' error in React app w/ Facebook

I'm a junior developer that's fairly new to using Facebook for Developers. I'm hitting a wall with the ReactJs application I'm building and could use your help!
My boss has requested a Grid representation of the Page Plugin, not the actual Plugin itself. For this project, he's requested I make and use a test 'Page' I've found that DevExtreme's Data Grid seems to be the best option in terms of the desired visual, and I'm trying to call my Facebook Page using the Graph API documentation. I know it's hitting at least the area I want it to with my console.log because it's returning the error message.
Here are the errors my browser is returning:
Access to fetch at 'https://www.facebook.com/Feeds-Tester-170107151801959/' from origin 'https://localhost:3000' 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. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
GET https://www.facebook.com/Feeds-Tester-170107151801959/ net::ERR_FAILED
The link you'll see referenced in my URL variable has been triple checked to be the correct link. Since I'm using NodeJS, I tried installing the CORS npm package but I'm not 100% sure where to put it to use it, I'm wondering if that's the cause of the issue?
Here's my full code snippet (I'm using VS Code, if that helps):
/*global FB*/
import React from 'react';
import { DataGrid, Editing, Scrolling, Lookup, Summary, TotalItem } from 'devextreme-react/data-grid';
import { Button } from 'devextreme-react/button';
import { SelectBox } from 'devextreme-react/select-box';
import CustomStore from 'devextreme/data/custom_store';
import { formatDate } from 'devextreme/localization';
import 'whatwg-fetch';
const URL = 'https://www.facebook.com/Feeds-Tester-170107151801959/';
const REFRESH_MODES = ['full', 'reshape', 'repaint'];
class Grid extends React.Component {
constructor(props) {
super(props);
this.state = {
fbData: null,
ordersData: new CustomStore({
key: 'OrderID',
load: () => this.sendRequest(`${URL}`, 'GET'),
}),
requests: [],
refreshMode: 'reshape'
};
this.clearRequests = this.clearRequests.bind(this);
this.handleRefreshModeChange = this.handleRefreshModeChange.bind(this);
var body = 'Reading JS SDK documentation';
FB.api('/me/feed', 'post', { message: body }, function(response) {
if (!response || response.error) {
console.log('Error occured');
} else {
console.log('Post ID: ' + response.id);
}
})
}
sendRequest(url, method, data) {
method = method || 'GET';
data = data || {};
this.logRequest(method, url, data);
if(method === 'GET') {
return fetch(url, {
method: method,
credentials: 'include',
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
'Access-Control-Allow-Origin': '*'
}
}).then(result => result.json().then(json => {
if(result.ok) return json.data;
throw json.Message;
}));
}
const params = Object.keys(data).map((key) => {
return `${encodeURIComponent(key) }=${ encodeURIComponent(data[key])}`;
}).join('&');
return fetch(url, {
method: method,
body: params,
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
},
credentials: 'include'
}).then(result => {
if(result.ok) {
return result.text().then(text => text && JSON.parse(text));
} else {
return result.json().then(json => {
throw json.Message;
});
}
});
}
logRequest(method, url, data) {
const args = Object.keys(data || {}).map(function(key) {
return `${key }=${ data[key]}`;
}).join(' ');
const time = formatDate(new Date(), 'HH:mm:ss');
const request = [time, method, url.slice(URL.length), args].join(' ');
this.setState((state) => {
return { requests: [request].concat(state.requests) };
});
}
clearRequests() {
this.setState({ requests: [] });
}
handleRefreshModeChange(e) {
this.setState({ refreshMode: e.value });
}
render() {
const { refreshMode, ordersData } = this.state;
return (
<React.Fragment>
<DataGrid
id="grid"
showBorders={true}
dataSource={ordersData}
repaintChangesOnly={true}
>
<Editing
refreshMode={refreshMode}
mode="cell"
allowAdding={true}
allowDeleting={true}
allowUpdating={true}
/>
<Scrolling
mode="virtual"
/>
<Lookup dataSource={ordersData} valueExpr="Value" displayExpr="Text" />
<Summary>
{/* <TotalItem column="CustomerID" summaryType="count" />
<TotalItem column="Freight" summaryType="sum" valueFormat="#0.00" /> */}
</Summary>
</DataGrid>
<div className="options">
<div className="caption">Options</div>
<div className="option">
<span>Refresh Mode: </span>
<SelectBox
value={refreshMode}
items={REFRESH_MODES}
onValueChanged={this.handleRefreshModeChange}
/>
</div>
<div id="requests">
<div>
<div className="caption">Network Requests</div>
<Button id="clear" text="Clear" onClick={this.clearRequests} />
</div>
<ul>
{this.state.requests.map((request, index) => <li key={index}>{request}</li>)}
</ul>
</div>
</div>
</React.Fragment>
);
}
}
export default Grid;
This is the link to the docs for the module I'm trying to reference
I'm trying to not bite off more than I can chew and just start with retrieving the data before I even think about manipulating it or sending any in return. Any insight or guidance you can provide would be greatly appreciated. Thank you!! :)
Do not use fetch with the Facebook URL, it won't let it happen on the browser, instead, use the Facebook API for everything you need to do with it
For example, instead of fetching the page, use the api with the page
FB.api('/Feeds-Tester-170107151801959', function(response) {
// ...
});
If you need to fetch the page, then you have to do it outside the browser environment or use a proxy like cors anywhere, but you can avoid that by using the Facebook API
I was also getting these error. I found that the pageId, I was using was wrong🤦‍♀️. These errors come only when your pageId is wrong or the domain is not whitelisted properly(I even tried with a ngrok url and it worked😵).
So the steps which I followed were:
In buisness.facebook.com go to inbox from sidebar and select chat plugin. [https://i.stack.imgur.com/rDk5d.png]
Click on setup to add your domain. [https://i.stack.imgur.com/exOi2.png]
Pick a setup method(standard for react/nextjs) and setup chat plugin(add language, domain, copy code and paste it). [https://i.stack.imgur.com/hDArZ.png]
You can add multiple domains. [https://i.stack.imgur.com/zGdgx.png]
You will get pageId already embedded. [https://i.stack.imgur.com/iRT13.png]
Use this code and paste it in _document.js file in nextjs. and after deploying it will work perfectly. For any confusion please let me know. Thanks, Happy Coding ☺

Failed to execute 'fetch' on 'Window': Request with GET/HEAD method cannot have body in react-admin

I am using react-adminframework, and I have written my own DataProvider. I am trying to accomplish that when an User is created, an instance of UserPossession is created as well. My code bellow accomplishes that, but react-admin Front-end just displays the warning message:
Failed to execute 'fetch' on 'Window': Request with GET/HEAD method cannot have body
I checked the Network tab in Developer Tools and every request to server is correct, there is no error. Which leaves me confused and stuck with this, because I have no idea what that warning means or why is it even occuring.
My code is a part of convertDataRequestToHTTP constant and looks like this:
if (resource === 'User') {
url = `${apiUrl}/${resource}`;
options.body = params.data;
httpClient(url, {
method: 'POST',
body: JSON.stringify(options.body),
})
.then(response => (
url = `${apiUrl}/Location`,
options.method = 'POST',
options.body = JSON.stringify({
"odata.type": "HardwareDatabase.UserPossession",
"Name": response.json.Login,
"UserId": response.json.Id
}),
httpClient(url, {
method: options.method,
body: options.body
})
));
}
If you have any questions regarding the code I can clarify.
Thank you for any ideas in advance.
Since you are stating that this code snippet is a part of convertDataRequestToHTTP I might see the issue. httpClient cannot be used in this constant since it creates duplicit calls to API or in your case, this Warning. Correct way would be to only state the options constant.
url = `${apiUrl}/${resource}`;
options.body = JSON.stringifiy(params.data);
options.method = 'POST';
Later in the constant that converts response from OData to mandatory React Admin format, state the httpClient.
params.data = {
"odata.type": "HardwareDatabase.UserPossession",
"Name": response.json.Login,
"UserId": response.json.Id
};
httpClient(`${apiUrl}/Location`, {
method: 'POST',
body: JSON.stringify(params.data),
})
Unfortunately, the GET method for XMLHttpRequest and fetch don't support request bodies.
A temporary work around I found was to use the axios library, which does let you send GET with request bodies.
const res = await axios.get("/api/devices", {
data: { deviceName: 'name' }
})

How to POST an XML with Angular http?

I'm having trouble using JavaScript to send xml. I've tried to emulate what many others have done, but I'm not getting success. I'm getting a XML Syntax Error: Please check the XML request to see if it can be parsed. with the code 80040B19.
Here's my code. I'm trying to use the USPS Address Validation API. On page 4 of this doc, there's more info.
const apiUrl = 'http://production.shippingapis.com/ShippingAPI.dll?API=Verify';
validate(address: Object): any {
const payload = this.xmlBuilder.buildObject({
AddressValidateRequest: {
$: { USERID: 'XXXXXXXXX' }, // api key hidden
Address: {
$: { ID: '0'},
FirmName: null,
Address1: address['address2'],
Address2: address['address1'], // NOT A TYPO, they swap it
City: address['city'],
State: 'NY',
Zip5: address['postal_code'],
Zip4: null
}
}
});
console.log(payload); // SEE BELOW
const headers = new Headers({ 'Content-Type': 'text/xml' });
const options = new RequestOptions({ headers: headers });
return this.http.post(this.apiUrl, { 'XML': payload }, options)
.map((res) => {
this.parseXMLStringToObject(res.text(), (err, result) => {
console.log(result);
});
});
}
Here's what my console.log on the payload reads. I've verified this to the letter, from the order of the xml tags, to what is required tag but optional value. I'm positive the payload is correct.
<AddressValidateRequest USERID="XXXXXXXXX">
<Address ID="0">
<FirmName/>
<Address1/>
<Address2>620 Eighth Avenue</Address2>
<City>New York</City>
<State>NY</State>
<Zip5>10018</Zip5>
<Zip4/>
</Address>
</AddressValidateRequest>
One thing that I can think of is I'm somehow not using the http correctly, and I'm sending a blank xml somehow.
On their docs, they have this listed:
https://servername/ShippingAPI.dll?API=Verify&XML=……..
I noticed I'm not doing a XML in the url, but I'm assuming that when I input the Content-Type: text/xml, that it get converted. I've also tried application/xml which give the same error.
From the documentation on USPS website it seems that the call isn't a POST with the XML as payload but a GET with XML (I suppose urlencoded) in the URL XML parameter.

Manage to download PDF stream with Blob in javascript

A web page (front) is calling a service which send a PDF stream as a response :
Here is the front code :
'click .btn': function (event) {
/.../
event.preventDefault();
Http.call(params, (err, res) => { // callback
if (err) console.log(err); // nothing
console.log({ res }); // print below result
const blob = new Blob(
[res.content],
{ type: `${res.headers['content-type']};base64` }
);
saveAs(blob, res.headers['content-disposition'].slice(21));
});
}
Here is the response from the server ( console.log(res) ) : { res : Object } printed in the console.
content: "%PDF-1.4↵1 0 obj↵<<↵/Title (��)↵/Creator (��)↵/Prod ..... lot of characters....%"
data: null,
statusCode: 200,
headers: {
connection: "close",
content-disposition: "attachment; filename=myDoc.pdf"
content-type: "application/pdf",
date: "date",
transfer-encoding: "chunked",
x-powered-by: "Express"
}
However, the PDF is downloaded with no content, it's full blank like corrupted ( But I can see the content in the string ). It works well with the CSV routes ( I send a csv as a stream and download it with the same method and I got the data).
I think there is something with the format %PDF ...% but I didn't manage to find something.
Note : With postman, it works, my PDF is saved, the page is not blank, I got the data. So there is something in the front I am not doing right.
I also tried with :
const fileURL = URL.createObjectURL(blob);
window.open(fileURL); // instead of saveAs
but the result is the same ( but in another tab instead of saved PDF ) blank page.
Any ideas ?
You probably forgot to specify the response type in your inital backend call - from the example you posted "arraybuffer" would be the correct one here, you can check all types here.

Chrome Extension - How to get HTTP Response Body?

It seems to be difficult problem (or impossible??).
I want to get and read HTTP Response, caused by HTTP Request in browser, under watching Chrome Extension background script.
We can get HTTP Request Body in this way
chrome.webRequest.onBeforeRequest.addListener(function(data){
// data contains request_body
},{'urls':[]},['requestBody']);
I also checked these stackoverflows
Chrome extensions - Other ways to read response bodies than chrome.devtools.network?
Chrome extension to read HTTP response
Is there any clever way to get HTTP Response Body in Chrome Extension?
I can't find better way then this anwser.
Chrome extension to read HTTP response
The answer told how to get response headers and display in another page.But there is no body info in the response obj(see event-responseReceived). If you want to get response body without another page, try this.
var currentTab;
var version = "1.0";
chrome.tabs.query( //get current Tab
{
currentWindow: true,
active: true
},
function(tabArray) {
currentTab = tabArray[0];
chrome.debugger.attach({ //debug at current tab
tabId: currentTab.id
}, version, onAttach.bind(null, currentTab.id));
}
)
function onAttach(tabId) {
chrome.debugger.sendCommand({ //first enable the Network
tabId: tabId
}, "Network.enable");
chrome.debugger.onEvent.addListener(allEventHandler);
}
function allEventHandler(debuggeeId, message, params) {
if (currentTab.id != debuggeeId.tabId) {
return;
}
if (message == "Network.responseReceived") { //response return
chrome.debugger.sendCommand({
tabId: debuggeeId.tabId
}, "Network.getResponseBody", {
"requestId": params.requestId
}, function(response) {
// you get the response body here!
// you can close the debugger tips by:
chrome.debugger.detach(debuggeeId);
});
}
}
I think it's useful enough for me and you can use chrome.debugger.detach(debuggeeId)to close the ugly tip.
sorry, mabye not helpful... ^ ^
There is now a way in a Chrome Developer Tools extension, and sample code can be seen here: blog post.
In short, here is an adaptation of his sample code:
chrome.devtools.network.onRequestFinished.addListener(request => {
request.getContent((body) => {
if (request.request && request.request.url) {
if (request.request.url.includes('facebook.com')) {
//continue with custom code
var bodyObj = JSON.parse(body);//etc.
}
}
});
});
This is definitely something that is not provided out of the box by the Chrome Extension ecosystem. But, I could find a couple of ways to get around this but both come with their own set of drawbacks.
The first way is:
Use a content script to inject our own custom script.
Use the custom script to extend XHR's native methods to read the response.
Add the response to the web page's DOM inside a hidden (not display: none) element.
Use the content script to read the hidden response.
The second way is to create a DevTools extension which is the only extension that provides an API to read each request.
I have penned down both the methods in a detailed manner in a blog post here.
Let me know if you face any issues! :)
To get a XHR response body you can follow the instructions in this answer.
To get a FETCH response body you can check Solution 3 in this article and also this answer. Both get the response body without using chrome.debugger.
In a nutshell, you need to inject the following function into the page from the content script using the same method used for the XHR requests.
const constantMock = window.fetch;
window.fetch = function() {
return new Promise((resolve, reject) => {
constantMock.apply(this, arguments)
.then((response) => {
if (response) {
response.clone().json() //the response body is a readablestream, which can only be read once. That's why we make a clone here and work with the clone
.then( (json) => {
console.log(json);
//Do whatever you want with the json
resolve(response);
})
.catch((error) => {
console.log(error);
reject(response);
})
}
else {
console.log(arguments);
console.log('Undefined Response!');
reject(response);
}
})
.catch((error) => {
console.log(error);
reject(response);
})
})
}
If response.clone().json() does not work, you can try response.clone().text()
I show my completed code if it can be some help. I added the underscore to get the request url, thanks
//background.js
import _, { map } from 'underscore';
var currentTab;
var version = "1.0";
chrome.tabs.onActivated.addListener(activeTab => {
currentTab&&chrome.debugger.detach({tabId:currentTab.tabId});
currentTab = activeTab;
chrome.debugger.attach({ //debug at current tab
tabId: currentTab.tabId
}, version, onAttach.bind(null, currentTab.tabId));
});
function onAttach(tabId) {
chrome.debugger.sendCommand({ //first enable the Network
tabId: tabId
}, "Network.enable");
chrome.debugger.onEvent.addListener(allEventHandler);
}
function allEventHandler(debuggeeId, message, params) {
if (currentTab.tabId !== debuggeeId.tabId) {
return;
}
if (message === "Network.responseReceived") { //response return
chrome.debugger.sendCommand({
tabId: debuggeeId.tabId
}, "Network.getResponseBody", {
"requestId": params.requestId
//use underscore to add callback a more argument, passing params down to callback
}, _.partial(function(response,params) {
// you get the response body here!
console.log(response.body,params.response.url);
// you can close the debugger tips by:
// chrome.debugger.detach(debuggeeId);
},_,params));
}
}
I also find there is a bug in chrome.debugger.sendCommand. If I have two requests with same URI but different arguments. such as:
requests 1:https://www.example.com/orders-api/search?limit=15&offer=0
requests 2:https://www.example.com/orders-api/search?limit=85&offer=15
The second one will not get the corrected responseBody, it will show:
Chrome Extension: "Unchecked runtime.lastError: {"code":-32000,"message":"No resource with given identifier found"}
But I debugger directly in background devtools, it get the second one right body.
chrome.debugger.sendCommand({tabId:2},"Network.getResponseBody",{requestId:"6932.574"},function(response){console.log(response.body)})
So there is no problem with tabId and requestId.
Then I wrap the chrome.debugger.sendCommand with setTimeout, it will get the first and second responseBody correctly.
if (message === "Network.responseReceived") { //response return
console.log(params.response.url,debuggeeId.tabId,params.requestId)
setTimeout(()=>{
chrome.debugger.sendCommand({
tabId: debuggeeId.tabId
}, "Network.getResponseBody", {
"requestId": params.requestId
//use underscore to add callback a more argument, passing params down to callback
}, _.partial(function(response,params,debuggeeId) {
// you get the response body here!
console.log(response.body,params.response.url);
// you can close the debugger tips by:
// chrome.debugger.detach(debuggeeId);
},_,params,debuggeeId));
},800)
}
I think the setTimeout is not the perfect solution, can some one give help?
thanks.

Categories

Resources