Can't Get Custom HTTP Header Response from Ajax getAllResponseHeaders - javascript

I do get the response data, but I can't get my custom HTTP header data.
Yes, this is a cross-domain request. I am doing an Ajax request with Javascript. I've tried this with XMLHttpRequest and also jQuery $.ajax. I've done my server settings, I have these set when sending data:
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, GET
I do get the response data that I want. But I can't get full HTTP header response.
With PHP, I set the following before sending the text response. So I assume that I should get it with getAllResponseHeaders().
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('My-Own-Test: nodatahere');
But here's what I got.
Content-Type: text/plain; charset=x-user-defined
Cache-Control: must-revalidate, post-check=0, pre-check=0
Expires: 0
It's missing the My-Own-Test. Just for reference sake, here's my Javascript:
var formData = new FormData();
formData.append('username', 'my_username');
formData.append('book_id', 'test password');
var xhr = new XMLHttpRequest();
xhr.open('POST', 'https://mydomain.com/proc.php', true);
xhr.overrideMimeType("text/plain; charset=x-user-defined");
xhr.onload = function(e) {
console.log(this.getAllResponseHeaders());
};
xhr.send(formData);
I even tried it with jQuery... same result.
var data_to_send = {
username: 'my_username',
password: 'test_password'
};
var ajaxObj;
ajaxObj = $.ajax({
url: "https://mydomain.com/proc.php",
data: data_to_send,
type: "POST",
beforeSend: function ( xhr ) {
xhr.overrideMimeType("text/plain; charset=x-user-defined");
}
})
.done(function ( data ) {
console.log( ajaxObj.getAllResponseHeaders() );
});
Still... no luck.
But if I go through Firebug or Chrome's Developer Tool, I can see that those tools do return full HTTP header information, including Content-Length, Content-Encoding, Vary, X-Powered-By, Set-Cookie, Server, and of course My-Own-Test.

I wanna thank jbl for pointing me to the right SO question. I got it now...
So, OK... the answer. If you ever wanted to set your own HTTP Header information, and then fetch it using cross-domain Ajax, or something like that, here are some extra HTTP Header you should set on your server side, before sending the response text.
header('Access-Control-Allow-Origin: *');
header("Access-Control-Allow-Methods: POST, GET");
header('Custom-Header: Own-Data');
header('Access-Control-Expose-Headers: Custom-Header');
Example above uses PHP. But use your own language, what ever you use to set them.
When I asked this question, I had all of that except Access-Control-Expose-Headers. After putting that in, my Javascript Ajax can read the content of HTTP Header Custom-Header.

Related

CORS-issue - "No 'Access-Control-Allow-Origin' header is present on the requested resource."

So I've been trying to pass data from my front-end to my back-end (however, I'm not very experienced within this area). The data comes through, however, if I try to insert the data into my MySQL-DB through PDO the browser gives me the following error:
Failed to load http://localhost:8888/post_recipe.php: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled."
JS
postToAPI = () => {
fetch(`http://localhost:8888/post_recipe.php`, {
method: 'POST',
headers: {
'Content-Type': 'text/html'
},
mode: 'cors',
body: JSON.stringify({
title: this.state.title,
description: this.state.description,
userID: this.props.userInfo.response.id,
name: this.props.userInfo.response.name,
stepByStep: (this.state.stepByStep),
recipeIngredients: (this.state.recipeIngredients),
profileImg: this.props.userInfo.response.picture.data.url
})
})
.then((response) => response.json())
.then((fetch) => {
console.log(fetch)
});
}
PHP
<?php
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Credentials: true');
header("Content-type: text/html; charset=utf-8");
header('Access-Control-Allow-Methods: GET, POST, PATCH, PUT, DELETE, OPTIONS');
header('Access-Control-Allow-Headers: Origin, Content-Type, X-Auth-Token');
$post = json_decode(file_get_contents('php://input'));
$array = json_decode(json_encode($post), True);
$pdo = new PDO(
"mysql:host=localhost:8889;dbname=veganify;charset=utf8",
"root",
"root"
);
$statement = $pdo->prepare(
"INSERT INTO posts (title, description, userID, name, stepByStep, recipeIngredients, profileImg)
VALUES (:title, :description, :userID, :name, :stepByStep, :recipeIngredients, :profileImg)"
);
$statement->execute(array(
":title" => $array["title"],
":description" => $array["description"],
":userID" => $array["userID"],
":name" => $array["name"],
":stepByStep" => $array["stepByStep"],
":recipeIngredients" => $array["recipeIngredients"],
":profileImg" => $array["profileImg"]
));
}
echo json_encode($array);
?>
So if I delete the MySQL-insertion, the data comes back to the front-end. I have been stuck here for a while now searching various forums for a solution. The error message says that the header is not present, however it is there, as you can see.
Any help would be much appreciated!
Cheers!
Good afternoon, this is because of the apache blocking requests from different sources ie if your backend is at http://yourdomain.com/client and your font-end is at localhost:3001 will cause a because they are of different (host) origins.
To solve:
Use the .htaccess file in your api / backend folder, for example, in my application my index.php is not in localhost / my-api / public directory then my .htaccess file in this directory directory localhost / my-api / public
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Origin: "*" (allow access from any origin)
Header set Access-Control-Allow-Origin: "http://motech-ui.example" (allow access from only "http://motech-ui.example" origin)
Access-Control-Allow-Origin: "http://motech-ui.example | http://other.domain" (allow access from two mentioned origins)
</IfModule>
Or config in apache.conf
Access-Control-Allow-Origin: "*" (allow access from any origin)
Access-Control-Allow-Origin: "http://motech-ui.example" (allow access from only "http://motech-ui.example" origin)
Access-Control-Allow-Origin: "http://motech-ui.example | http://other.domain" (allow access from two mentioned origins)
CORS in Javascript and PHP works like.
OPTIONS method request will be triggered from browser side.
Server side (PHP) should accept the OPTIONS request, by responding 'OK'.
Now a proper POST request will be triggered from browser side, which will go to your functionality location where your PHP code will gets executed.
if ($_SERVER["REQUEST_METHOD"] === "OPTIONS") {
//location where you can handle your request and respond ok
echo 'OK';
}
If you can not control the sever side, you can work around like me on
Client side only.
If you can control server side, you can use server side solution. I am not discus it here.
Only on client side, work around is
use dataType: 'jsonp',
async function get_ajax_data(){
var _reprojected_lat_lng = await $.ajax({
type: 'GET',
dataType: 'jsonp',
data: {},
url: _reprojection_url,
error: function (jqXHR, textStatus, errorThrown) {
console.log(jqXHR)
},
success: function (data) {
console.log(data);
// note: data is already json type, you just specify dataType: jsonp
return data;
}
});
} // function

Error HTTP GET object list

I get an error when I try to retrieve a list of objects from a link (php server).
Blocking of a multi-origin request (cross-origin request): the "same
source" policy does not allow access to the remote resource located at
http: //localhost/eReport/index.php. Reason:
"Access-control-authorization-origin" token missing in the CORS
"Access-Control-Allow-Headers" CORS header.
I added a header like this tuto that is recommended on this link but I still have this error.
Can you help me please ?
My Service page:
#Injectable()
export class ReportService{
private baseUrl: string = 'http://localhost/report/reports.php';
constructor(private http : Http){}
getAll(): Observable<Report[]>{
let report$ = this.http
.get(`${this.baseUrl}`, { headers: this.getHeaders()})
.map(mapReports);
return report$;
}
private getHeaders(){
// I included these headers because otherwise FireFox
// will request text/html
let headers = new Headers();
headers.append('Accept', 'application/json');
headers.append('Content-Type', 'application/x-www-form-urlencoded;charset=UTF-8');
return headers;
}
get(id: number): Observable<Report> {
let report$ = this.http
.get(`${this.baseUrl}/report/${id}`, {headers: this.getHeaders()})
.map(mapReport);
return report$;
}
My php page
header("Access-Control-Allow-Origin: *");
$tab = array(
array('id'=> '12', 'name'=> 'test','description' => '2018-04-01','url'=>'../../../assets/img/chat1.png' ),
array('id'=> '13', 'name'=> 'test','description' => '2018-04-01','url'=>'../../../assets/img/highcharts.png' )
);
echo json_encode($tab);
?>
Perhaps the quickest fix is to change your base url in the Angular app to /report/reports.php if the requests are going to the same server that served the app.
Your request is not working because when the client sends content of type application/json, the browser doesn't send the request right away. If you restart your browser then observe the network tab you will notice that instead of your GET, an OPTIONS request is first send, that includes headers similar to these:
Origin: yourserver
Access-Control-Request-Method: GET
Access-Control-Request-Headers: Content-Type, Accept
In this scenario, the browser expects the server to return not just the Access-Control-Allow-Origin header (which you're already doing), but all of these:
Access-Control-Allow-Origin: yourserver (or *)
Access-Control-Allow-Methods: GET (or a list eg: GET, POST, OPTIONS)
Access-Control-Allow-Headers: Content-Type, Accept (the same headers from above)
So you need to read the request headers from the previous block, and use their values when setting the response headers. If you have the apache_request_headers() method it's pretty easy. You can also get them from the $_SERVER superglobal.
// set required headers:
header("Access-Control-Allow-Origin: $_SERVER[HTTP_ORIGIN]");
header("Access-Control-Allow-Methods: $_SERVER[HTTP_ACCESS_CONTROL_REQUEST_METHOD]");
header("Access-Control-Allow-Headers: $_SERVER[HTTP_ACCESS_CONTROL_REQUEST_HEADERS]");
See this helpful article

ajax request to symfony api returns No 'Access-Control-Allow-Origin' header is present

I am making simple application with React that sends ajax requests to API made with Symfony. I am developing both the react app and symfony api. I am sending request from localhost:3000 to localhost:8000. Here is the ajax request that I am sending
addUser (data) {
console.log('made it')
let request = {
method: 'post',
url: 'http://127.0.0.1:8000/user/post',
data: JSON.stringify({'username': data}),
contentType: 'application/json'
}
$.ajax(request)
.done(data => this.addUserSuccess(data))
.fail(err => this.addUserFail(err))
}
and here is the Symmfony app that takes care of the request
/**
* Creates a new user entity.
*
* #Route("/post", name="user_new")
* #Method({"GET", "POST"})
*/
function newAction(Request $request ) {
echo $request;
$body = $request->getContent();
$body = json_decode($body,true);
$username = $body['username'];
$user = new User($username);
$em = $this->getDoctrine()->getManager();
$em->persist($user);
$em->flush();
return new JsonResponse($user,200,array('Access-Control-Allow-Origin'=> '*'));
}
I am so far in the beginning and as you can see I am creating new user without password, security or anything. I just want to make it work and be able to send request from the app to the api. Here is the result
XMLHttpRequest cannot load http://127.0.0.1:8000/user/post. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. The response had HTTP status code 405.
I have seen many questions like this one before and one of the answers was to return JsonResponse with the header and as you can see it does not work.
Here is one of the quenstions whose answer I followed - Origin is not allowed by Access-Control-Allow-Origin but unfortunately with no success.
Can you tell me how to fix it? Thank you in advance!
Here's what I'm doing for the same situation. In app/config/config_dev.yml, add a new service. Putting this in config_dev.yml means this will only affect requests through app_dev.php.
services:
app.cors_listener:
class: AppBundle\Security\CorsListener
tags:
- { name: kernel.event_listener, event: kernel.response, method: onKernelResponse }
And the contents of AppBundle/Security/CorsListener.php:
<?php
namespace AppBundle\Security;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
// Based on http://stackoverflow.com/a/21720357
class CorsListener
{
public function onKernelResponse(FilterResponseEvent $event)
{
$responseHeaders = $event->getResponse()->headers;
$responseHeaders->set('Access-Control-Allow-Headers', 'origin, content-type, accept, credentials');
$responseHeaders->set('Access-Control-Allow-Origin', 'http://localhost:8080');
$responseHeaders->set('Access-Control-Allow-Credentials', 'true');
$responseHeaders->set('Access-Control-Allow-Methods', 'POST, GET, PUT, DELETE, PATCH, OPTIONS');
}
}
You need to set the correct headers on your PHP file.
header('Access-Control-Allow-Origin: *');

XMLHttpRequest/ajax set Content-Type

I've tried both these things separately:
note: url is a variable containing a https url and jsonString contains a valid json string
var request = new XMLHttpRequest();
try{
request.open("POST", url);
request.setRequestHeader('Accept', 'application/json');
request.send(jsonString);
} catch(e) {
alert(e);
}
and
var options = {
type: "POST",
url: url,
dataType: "json",
data: jsonString,
accept: "application/json"
};
$.ajax(options)
The problem is the system we are posting to requires a header Content-Type with a value "application/json".
With the way things are right now, the method used is POST, the Accept header is "application/json", and the Content-Type defaults to "application/x-www-form-urlencoded; charset=UTF-8"
In the first example, if request.setRequestHeader('Content-Type', 'application/json'); is added 1 line above or below the Accept header, the method used changes to OPTIONS, the Accept header changes to "text/html,application/xhtml+xml,application/xml;q=0.9,/;q=0.8" and the Content-Type header disappears as if it wasn't seen.
In the second example, if contentType: "application/json" is added anywhere within options, the same thing happens that happened in the first example.
What is the proper way to set a Content-Type header in ajax or XMLHttpRequest?
Edit: I should add that using the firefox rest client plugin, the json string, url, and accept and content type headers all work fine. We just can't seem to get the content header set on our own page.
In the first example, if request.setRequestHeader('Content-Type', 'application/json'); is added 1 line above or below the Accept header, the method used changes to OPTIONS
This is because you are making a cross origin request from JS embedded in a webpage. Changing the content-type (to one that you couldn't make with a simple HTML form) triggers a preflight request asking permission from the server to make the actual request.
You need to set up the server to respond with appropriate CORS headers to grant permission.
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 01:15:39 GMT
Access-Control-Allow-Origin: http://your.site.example.com
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: Content-Type
Then the browser will make the POST request you are asking it to make.

CORS: Can't get POST request body.

I am trying to make request with XMLHttpRequest from file://example.html to http://localhost/index.php. I read a lot about CORS(in this case origin is null, this is OK.) and i have no idea what i am doing wrong.
My request finishes well but the $_POST is empty! Except if i set "Content-type: application/x-www-form-urlencoded". But "text/plain" or "application/json" gives no result in $_POST... Why?
xhr.open("POST", "http://localhost/index.php", true);
xhr.setRequestHeader("Content-Type", "application/json");
xhr.onreadystatechange = handler;
xhr.send({'a':'12'});
You are probably doing one of these two things wrong:
If the content-type is not application/x-www-form-urlencoded, CORS must send a preflight request. That means that the browser will send before doing the POST request an OPTIONS request, which is used to determine if the POST request is allowed. Take a look here how this works.
Secondly, if you use xhr.setRequestHeader("Content-Type", "application/json"), the $_POST parameters will not be filled with parameters, this is only the case for application/x-www-form-urlencoded. To get the JSON you send, you will have to do:
<?php
$input = json_decode(file_get_contents("php://input"), true);
echo $input['a']; //echoes: 12
For more info, see this question.
Furthermore, if you go into the debugging facilities of any decent browser, it will create an error message if the CORS request is not allowed, please be sure to check if the CORS request was actually made by the browser.
I hope this helps you.
complementing #user23127 response
server side should have something like this to respond to the OPTIONS preflight request:
if (request.method === 'OPTIONS') {
htmlRes = HttpResponse()
htmlRes['Access-Control-Allow-Origin']='*' // or your not origin domain
htmlRes['Access-Control-Allow-Methods']='*' // or POST, GET, PUT, DELETE
htmlRes['Access-Control-Allow-Headers']='*' // Content-Type, X-REQUEST
}
// the rest of the code as if it was not a CORS request

Categories