I am trying to post user data to a PHP RESTful API from my ionic app. I tried searching for a solution but was of no help. I have created a provider containing a function namely "onSignup(signupForm)" which is being called on button click.
The code is as follows:
signup(username: string,email: string,password: string): void {
let headers = new HttpHeaders();
headers = headers.set("Content-Type","application/json; charset=UTF-8");
let body= {
name:username, email:email, password:password
};
this.http.post('http://www.something.com/register', JSON.stringify(body),
{headers: headers})
.subscribe(data => {
console.log(data);
});
this.storage.set(this.HAS_LOGGED_IN, true);
this.setUsername(username);
this.events.publish('user:signup');
};
The code for the api is as:
<?php
header("Access-Control-Allow-Origin:*");
header("Content-Type: application/json; charset=UTF-8");
require_once '../include/DbHandler.php';
require_once '../include/PassHash.php';
require '.././libs/Slim/Slim.php';
\Slim\Slim::registerAutoloader();
$app = new \Slim\Slim();
/**
* ----------- METHODS WITHOUT AUTHENTICATION -------------------------------
--
*/
/**
* User Registration
* url - /register
* method - POST
* params - name, email, password
*/
$app->post('/register', function() use ($app) {
file_put_contents("logs.txt","/register Route has been visited");
// check for required params
verifyRequiredParams(array('name', 'email', 'password'));
$response = array();
// reading post params
$name = $app->request->post('name');
$email = $app->request->post('email');
$password = $app->request->post('password');
// validating email address
validateEmail($email);
$db = new DbHandler();
$res = $db->createUser($name, $email, $password);
if ($res == USER_CREATED_SUCCESSFULLY) {
$response["error"] = false;
$response["message"] = "You are successfully registered";
} else if ($res == USER_CREATE_FAILED) {
$response["error"] = true;
$response["message"] = "Oops! An error occurred while registereing";
} else if ($res == USER_ALREADY_EXISTED) {
$response["error"] = true;
$response["message"] = "Sorry, this email already existed";
}
// echo json response
echoRespnse(201, $response);
});
The error I receive is
Failed to load resource: the server responded with a status of 404 (Not Found).
Failed to load http://www.something.com/register: Response for preflight has invalid HTTP status code 404
This API is working perfectly in Postman, but is facing the issue when I am running the app in Chrome.
Is there something I am missing in the API or during the POST call?
Please help. Thanks in Advance.
Edit:
I have added the Network Tab screenshot. This is what I am getting in my Request and Response Headers. I guess there might be a mismatch in the two headers and definitely it can't be a CORS issue because I can make GET calls without any CORS issue.
Added the console tab screenshot with the errors:
Since it is working from Postman but not your application I would take a good look into CORS. You need to set your headers when a request comes in, for post requests the Angular HttpClient will send an OPTIONS request.
I don't use PHP much, but maybe something like this would work
if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type');
header('Content-Length: 0');
header('Content-Type: application/json');
die();
}
Edit: Since you are using the Slim Framework I assume by your provided code. You can address OPTIONS requests like so as described per the Slim Framework v2 Docs (Not sure what version you are using).
$app->options('/register', function ($app) {
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type');
header('Content-Length: 0');
header('Content-Type: application/json');
die();
});
Or you could maybe set the headers like so, as described by
https://www.slimframework.com/docs/v2/response/headers.html
$app->response->headers->set('Access-Control-Allow-Origin', '*');
$app->response->headers->set('Access-Control-Allow-Methods', 'POST, OPTIONS');
$app->response->headers->set('Access-Control-Allow-Headers', 'Content-Type');
$app->response->headers->set('Content-Type', 'application/json');
try this
header('Access-Control-Allow-Origin: *');
$dados = file_get_contents('php://input');
you will get a JSON from your angular request...
Related
I am new to Angular9, I have tried to save data by calling a php API from my angular9 application, but geting the following error.
I have test this service from postman, which is working fine and save data successfully
Access to XMLHttpRequest at 'http://127.0.0.1/angularCRUDservices/user/saveEmployee' from origin 'http://localhost:4200' has been blocked by CORS policy: Request header field access-control-allow-origin is not allowed by Access-Control-Allow-Headers in preflight response.
**Please Note:** get method is working fine to fetch data,
my Angular service:
reqHeader = new HttpHeaders(
{
'Content-Type': 'application/json',
'No-Auth':'True',
'Access-Control-Allow-Origin' : '*',
'Access-Control-Allow-Header':'Access-Control-Allow-Origin,X-Requested-With,Content-Type,Access',
'Access-Control-Allow-Methods':'GET,POST,DELETE,PATCH,PUT,OPTIONS'
}
);
constructor(private httpClient:HttpClient){}
saveEmployee(formData:Employee){
console.log(formData);
this.httpClient.post<{response:any,success:boolean}>("http://127.0.0.1/angularCRUDservices/user/saveEmployee",formData,{
headers : this.reqHeader
})
.subscribe((response)=>{
console.log(response);
})
}
php service code:
setting headers in constructor:
public function __construct()
{
parent::__construct();
$this->load->helper('url');
$this->load->model('user_model','usr');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Header: Access-Control-Allow-Origin,X-Requested-With,Content-Type,Access');
header("Access-Control-Allow-Methods: GET,POST,DELETE,PATCH,PUT,OPTIONS");
header('Content-Type: application/json, charset=utf-8');
}
service:
public function saveEmployee()
{
$input = array();
try
{
$UserID = $this->input->post('id');
$input['name'] = $this->input->post('name');
$input['gender'] = $this->input->post('gender');
$input['email'] = $this->input->post('email');
$input['mobile'] = $this->input->post('mobile');
$input['department'] = 'test';//$this->input->post('department');
$input['isActive'] = 1;//$this->input->post('isActive');
$input['photo'] = 'testphoto';//$this->input->post('photo');
$output["response"] = $this->usr->saveUser($input,$UserID); // call model query to save data into DB
$output["success"] = true;
}
catch (Exception $ex)
{
$output["success"] = false;
$output["error"] = $ex->getMessage();
}
echo json_encode((object)$output);
exit;
}
if this is for development and not production,you can use a proxy to get arround the issue. add a json file to your root project named 'proxy.configuration.json'
remember to change the target to your api in the example below
{
"/api/*": {
"target": "https://localhost:44362",
"secure": false,
"logLevel": "debug",
"changeOrigin": true
}
}
then run ng serve --proxy-config proxy.config.json
you have to add Authorization header key in Access-Control-Allow-Headers(in the backend)
Access-Control-Allow-Headers: Authorization (when you give like this it accepts specified headers only.means if you want to accept another key like authorization you have to mention that key name)
or
you can give like this also
Access-Control-Allow-Headers: *
I have been struggling with a strange issue for about a week now. I have searched through the answers here and elsewhere on the internet and I'm not quite sure what my specific issue might be. I do however think the error message I am getting doesn't have anything to do with my actual error. I thank you for any help or suggestions you might have.
My setup is as follows (all running locally):
Frontend website - Angular - running on standard ng serve
Backend API - PHP / MySQL - hosted locally via XAMPP
The error:
{"headers":{"normalizedNames":{},"lazyUpdate":null,"headers":{}},"status":0,"statusText":"Unknown Error","url":"http://192.168.64.2/resourcer/api/menu/47693eb3-ca82-467b-af68-020150a5e4a6","ok":false,"name":"HttpErrorResponse","message":"Http failure response for http://192.168.64.2/resourcer/api/menu/47693eb3-ca82-467b-af68-020150a5e4a6: 0 Unknown Error","error":{"isTrusted":true}}
The concept:
Log in, authenticate on the php side, get jwt token.
The jwt token has a property called 'access'. I use this to return the menu based on the role.
Once I receive the jwt, I set the user object, append the jwt to bearer token auth header.
Call the retrieve menu call with the access property received from the server.
All of this works up until I change user. I have added 2 users to test the different menu items coming back, and when I log a user out (clear local storage), I try the second user's credentials.
I log in successfully, get the jwt and the user object, but when I request the menu I get the error message. I cannot get past this at all. The only way this gets fixed is by commenting all the code required to return the menu and just echo 'ok'. Then I do a request, get the ok, uncomment the code and then it's all back to normal until I log out again.
Have no idea what on earth is going on. Here is my code:
Angular Interceptor Service:
export class InterceptorService implements HttpInterceptor {
constructor(private authService: AuthService) {}
intercept(
request: HttpRequest<any>,
next: HttpHandler,
): Observable<HttpEvent<any>> {
const currentUser = this.authService.currentUserValue;
if (currentUser && currentUser.token) {
request = request.clone({
setHeaders: {
'Content-Type': 'application/json; charset=utf-8',
Accept: 'application/json',
Authorization: `Bearer ${currentUser.token}`,
},
});
} else {
request = request.clone({
setHeaders: {
'Content-Type': 'application/json; charset=utf-8',
Accept: 'application/json',
},
});
}
return next.handle(request);
}
}
Angular Auth Service:
signIn(signinCredentials: AuthCredentials) {
return this.dataService.signIn(signinCredentials).pipe(
map((data) => {
const helper = new JwtHelperService();
const decoded = helper.decodeToken(data.jwt);
const user: User = decoded.data;
user.token = data.jwt;
localStorage.setItem('currentUser', JSON.stringify(user));
this.currentUserSubject.next(user);
return user;
}),
);
}
logout() {
localStorage.removeItem('currentUser');
localStorage.removeItem('navItems');
this.currentUserSubject.next(null);
}
Angular Login Page:
signIn() {
this.submitted = true;
this.loading = true;
this.authService
.signIn(this.signinCredentials)
.pipe(first())
.subscribe(
(data) => {
this.currentUser = this.authService.currentUserValue;
this.getMenu();
},
(error) => {
this.error = error;
this.loading = false;
},
);
}
getMenu() {
this.dataService.getNavigationItems(this.currentUser.access).subscribe(
(menu) => {
if (menu) {
this.envService.setNavItems(menu.menu);
this.router.navigate([this.returnUrl]);
} else {
this.authService.logout();
location.reload(true);
}
},
(error) => {
this.authService.logout();
location.reload(true);
},
);
}
Now on my PHP side, I use an .htaccess file to redirect my URL:
RewriteEngine on
RewriteRule app/api/ app/api/index.php
PHP Index:
<?php
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");
header("Access-Control-Allow-Methods: GET, POST, PATCH, PUT, DELETE, OPTIONS");
header("Access-Control-Max-Age: 3600");
header("Access-Control-Allow-Headers: Origin, Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
define('PROJECT_ROOT_PATH', __DIR__);
include_once 'config/db.php';
--- Controller imports etc happen here
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$uri = explode('/', $uri);
$requestMethod = $_SERVER["REQUEST_METHOD"];
$headerToken = getBearerToken();
if (isset($uri[3])) {
switch ($uri[3]) {
case 'users':
$userId = null;
if (isset($uri[4])) {
$userId = (int) $uri[4];
}
$controller = new UserController($db, $requestMethod, $userId, $headerToken);
$controller->processRequest();
break;
case 'companies':
$companyReference = null;
if (isset($uri[4])) {
$companyReference = $uri[4];
}
$controller = new CompanyController($db, $requestMethod, $companyReference, $headerToken);
$controller->processRequest();
break;
case 'login':
$controller = new LoginController($db);
$controller->login();
break;
case 'menu':
$roleGuid = null;
if (isset($uri[4])) {
$roleGuid = $uri[4];
}
$controller = new MenuController($db, $roleGuid, $headerToken);
$controller->getMenuItems();
break;
default:
header("HTTP/1.1 404 Not Found");
exit();
}
} else {
header("HTTP/1.1 404 Not Found");
exit();
}
function getAuthorizationHeader()
{
$headers = null;
if (isset($_SERVER['Authorization'])) {
$headers = trim($_SERVER["Authorization"]);
} else if (isset($_SERVER['HTTP_AUTHORIZATION'])) {
$headers = trim($_SERVER["HTTP_AUTHORIZATION"]);
} elseif (function_exists('apache_request_headers')) {
$requestHeaders = apache_request_headers();
$requestHeaders = array_combine(array_map('ucwords', array_keys($requestHeaders)), array_values($requestHeaders));
if (isset($requestHeaders['Authorization'])) {
$headers = trim($requestHeaders['Authorization']);
}
}
return $headers;
}
function getBearerToken()
{
$headers = getAuthorizationHeader();
if (!empty($headers)) {
if (preg_match('/Bearer\s(\S+)/', $headers, $matches)) {
return $matches[1];
}
}
return null;
}
When I mentioned that I comment out the controller code with an echo ok, and it works, happens in this index file.
I'm stumped.
I am working with CodeIgniter Rest server, I am making PUT request . Everything works fine in the chrome and firefox, but in the internet explorer I keep getting an error saying Request method PUT was not present in the Access-Control-Allow-Methods list., i even added the response headers to allow the different methods , following is the rest service
public function service_put()
{
if (!$this->_allow) return;
$data = $this->_put_args;
if(isset($data))
{
// have my arguments
try{
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST,PUT,GET,DELETE');
header('Access-Control-Allow-Headers: Origin,X-Requested-With,Content-Type, Accept');
$this->response(['done' => TRUE], REST_Controller::HTTP_OK); // (200) HTTP response code
}
catch(Exception $e)
{
$this->response(array('error' => $e->getMessage()), $e->getCode());
}
return;
}
else
{
$this->returnBadRequest();
return;
}
}
This is my rest.php file
<?php
chdir('../../..');
require_once 'SugarWebServiceImplv4_1_custom.php';
$webservice_path = 'service/core/SugarRestService.php';
$webservice_class = 'SugarRestService';
$webservice_impl_class = 'SugarWebServiceImplv4_1_custom';
$registry_path = 'custom/service/v4_1_custom/registry.php';
$registry_class = 'registry_v4_1_custom';
$location = 'custom/service/v4_1_custom/rest.php';
require_once 'service/core/webservice.php';
This is my SugarWebServiceImplv4_1_custom.php file where i have written custom methods
<?php
header("Access-Control-Allow-Origin: *");
header("Access-Control-Max-Age: 3600");
header("Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With");
if(!defined('sugarEntry')){
define('sugarEntry', true);
}
require_once 'service/v4_1/SugarWebServiceImplv4_1.php';
class SugarWebServiceImplv4_1_custom extends SugarWebServiceImplv4_1
{
public function custom_test($username)
{
$arr = array ('a'=>$username,'b'=>22,'c'=>32,'d'=>44,'e'=>55);
return json_encode($arr);
die;
}
}
This is my registry.php file where i have registered my custom method
<?php
require_once 'service/v4_1/registry.php';
class registry_v4_1_custom extends registry_v4_1
{
protected function registerFunction()
{
parent::registerFunction();
$this->serviceClass->registerFunction('custom_test',
array(
'username'=>'xsd:string),
array(
'return'=>'tns:get_array')
);
}
}
The problem is when i am passing the the data through get method Like this
http://www.example.com/custom/service/v4_1_custom/rest.php?method=custom_test&input_type=json&response_type=json&rest_data=
{"username":"some
username"}
i am getting the result but i dont know how to pass it through post method through IOS application. I tried to pass it but I am not getting anything in username.
I checked the response through curl as well , it is working using curl, But i have to connect it to IOS.
Help will be appreciated
Actually we are building a Hybrid app for IOS using Angular 5 and Ionic 3
Here is the code
auth-services.ts
public login(credentials){
if(credentials.username === null || credentials.password === null){
return Observable.throw("Please enter credentials");
} else {
this.username1 = credentials.username;
this.password1 = credentials.password;
return Observable.create(observer =>{
// At this point make a request to your backend to make a real check!
this.method1 = "custom_test";
this.inputType = "JSON";
this.responseType = "JSON";
this.encryptionValue = "PLAIN";
this.bodyData = {}; //get method calling
console.log(JSON.stringify(this.bodyData));
//Sending the Username and Password to the Web Server for authentication. Change the URL Get the response message
this.servicesProvider.restApi("post","http://exmaple.com/custom/service/v4_1_custom/rest.php",this.bodyData).then(
(res) => {
console.log("Response stringify :",JSON.stringify(res));
console.log("Response parse :", res);
console.log("Status :",res.status);
this.response = res.status; //TODO: Replace res.username with res.message as we have to check for user exist or not.
if(this.response == "success out") {
this.success = true;
this.storage.set("status",this.response); //Username value stored in localstorage
this.currentUser = new User('Simon', 'saimon#devdactic.com');
observer.next(this.success);
observer.complete();
} else {
this.success = false;
observer.next(this.success);
observer.complete();
}
}
);
}
Here is the services.ts file. this is a common rest api file for sending rest api requests.
restApi(method,url,data) {
console.log("inside restApi");
switch(method) {
case 'post' : {
console.log("Inside Post Method");
/*
return this.httpClient.post(url,data)
.subscribe(
(res:any) => {
console.log("POST response below");
console.log(res.username);
this.responseData = JSON.stringify(res);
console.log("ResponseData Value");
console.log(this.responseData);
return this.responseData;
}); */
let headers = new Headers({'content-type':'application/json'});
let options = new RequestOptions({ headers:this.headers });
this.responseFromFunction = this.http.post(url,data).toPromise()
.then(this.extractData)
.catch(this.handleError);
break;
}
case 'get' : {
console.log("Inside Get Method");
let headers = new Headers({'content-type':'application/json'});
let options = new RequestOptions({ headers:this.headers });
this.responseFromFunction = this.http.get(url, options).toPromise()
.then(this.extractData)
.catch(this.handleError);
break;
}
case 'put' : {
console.log("Inside Put Method");
this.responseFromFunction = this.httpClient.put(url,data)
.subscribe((res:any) => {
console.log(res);
});
break;
}
case 'delete' : {
console.log("Inside Delete Method");
this.responseFromFunction = this.httpClient.delete(url)
.subscribe((res:any) => {
console.log(res);
});
break;
}
default : {
this.responseFromFunction = {"message":"error"};
console.log("Unknow Method Entered. Or write method in small lowercase only");
// return "Invalid Method";
}
}
console.log("Outside switch case");
console.log(this.responseFromFunction);
return this.responseFromFunction;
}
private extractData(res: Response) {
// console.log("Resp :", res.json());
// console.log("Stringy :", JSON.stringify(res));
return res.json();
}
private handleError(error: any): Promise<any> {
console.error('An error occurred', error);
return Promise.reject(error.message || error);
}
}
here is the postman response
I am not getting how to pass username in rest_data
IF you are using Angular 5 then :
Documentation read it
Making a POST request
Apps often POST data to a server. They POST when submitting a form. In the following example, the HeroesService posts when adding a hero to the database.
app/heroes/heroes.service.ts (addHero)
/** POST: add a new hero to the database */
addHero (hero: Hero): Observable<Hero> {
return this.http.post<Hero>(this.heroesUrl, hero, httpOptions)
.pipe(
catchError(this.handleError('addHero', hero))
);
}
The HttpClient.post() method is similar to get() in that it has a type parameter (you're expecting the server to return the new hero) and it takes a resource URL.
It takes two more parameters:
hero - the data to POST in the body of the request.
`httpOptions` - the method options which, in this case, specify required headers.
Of course it catches errors in much the same manner described above.
The HeroesComponent initiates the actual POST operation by subscribing to the Observable returned by this service method.
app/heroes/heroes.component.ts (addHero)
this.heroesService.addHero(newHero)
.subscribe(hero => this.heroes.push(hero));
When the server responds successfully with the newly added hero, the component adds that hero to the displayed heroes list.
Edited Answer:
I saw your postman screenshot you are passing username
This link will help you
I have a issue with my slim app, i want send json responses but with customed headers. My code is like follow:
index.php
require 'vendor/autoload.php';
require 'app/config.php';
require 'app/libs/api.cs.php';
$app = new Slim\App(
[
"settings" => $config,
"apics" => function() { return new APIHelper(); } //This is a class that contain a "helper" for api responses
]
);
require 'app/dependences.php';
require 'app/middleware.php';
require 'app/loader.php';
require 'app/routes.php';
// Run app
$app->run();
app/libs/api.cs.php (The "helper")
<?php
class APIHelper
{
public function sendResponse($response, $status='success' ,$code = 200, $message = "", $data = null)
{
$arrResponse = array();
$arrResponse['status'] = $status;
$arrResponse['code'] = $code;
$arrResponse['message'] = $message;
$arrResponse['data'] = $data;
return $response
->withHeader('Access-Control-Allow-Origin', '*')
->withHeader('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Accept, Origin, Authorization, AeroTkn')
->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')
->withHeader('Content-Type','application/json')
->withHeader('X-Powered-By','My API Server')
->withJson($arrResponse,$code);
}
}
my routes file (app/routes.php)
$app->group('/foo', function () {
$this->get('', function ($req, $res, $args) {
return $this->apics->sendResponse($res, 'success' ,200, "Foo API Index By Get", null);
});
$this->post('', function ($req, $res, $args) {
try{
$oBody = $req->getParsedBody();
return $this->apics->sendResponse($res, 'success' ,200, "Foo API POST Response", $oBody);
}
catch(\Exception $ex){
return $this->apics->sendResponse($res, 'error' ,500, "Process Error", array('error' => $ex->getMessage()));
}
});
});
When i trying to run my app with request body, the result is the follow:
Headers:
connection →Keep-Alive
content-type →text/html
date →Wed, 30 Aug 2017 02:22:56 GMT
keep-alive →timeout=2, max=500
server →Apache
transfer-encoding →chunked
Body (returns as simple text and not json encoded)
{"status":"success","code":200,"message":"Foo API POST Response","data":{"one":"1", "two":"2"}}
I've trying put this class as a middleware, but i'm some confused in these subject.
Can you help me telling me if these method is good or where i'm bad.
Thanks to all and i hope for your answers! Nice day
Using Middleware is the ideal answer for your problem
Just add this function in your middeleware file
$app->add(function ($req, $res, $next) {
$response = $next($req, $res);
return $response
->withHeader('Access-Control-Allow-Origin', 'http://mysite')
->withHeader('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Accept, Origin, Authorization')
->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
->withHeader('Content-Type','application/json');
->withHeader('X-Powered-By','My API Server');
});
I found the "error" was a kindergarden issue hahaha, I've download all my code from the web server for test in my machine, I have the same result, but i found that all my files had strange characters at start, so i re-save the files as utf-8 and the problem is solved. Little details that can create headaches!. Thanks to Nica and Ramy. Ramy: the solution was excellent, now the code are more organizated, i take this practice. Good day to all.