I've set up a webhook with Stripe, which calls a serverless function when it's triggered.
The function is intended to update an entry in my database when it's called, suggesting that a user has signed up for a premium account.
When I run this locally, the webhook works perfectly. It triggers the API, updates the user and processes the payment.
However, when it gets run on live, I continually get a 308 error saying:
Redirecting to my-app-url.com
Here's the code for my function:
import { buffer } from "micro"
import { createClient } from "#supabase/supabase-js";
require("dotenv").config();
const stripe = require("stripe")(process.env.STRIPE_LIVE_KEY)
const endpointSecret = process.env.STRIPE_WEBHOOK_SECRET
const supabaseUrl = process.env.REACT_APP_SUPABASE_URL
const supabaseAnonKey = process.env.REACT_APP_SUPABASE_ANON_KEY
const supabase = createClient(supabaseUrl, supabaseAnonKey)
module.exports = async (req, res) => {
const signature = req.headers["stripe-signature"]
const reqBuffer = await buffer(req)
let event
try {
event = stripe.webhooks.constructEvent(reqBuffer, signature, endpointSecret)
} catch (err) {
console.log(err)
return res.status(400).send(`Webhook error: ${err.message}`)
}
if (event.type === "checkout.session.completed") {
console.log("Checkout completed!")
const userId = String(event.data.object.client_reference_id)
console.log(userId)
const { error } = await supabase.from('profiles').update({ premium: 'true' }).eq('id', userId)
if (error) {
console.log(error)
}
}
res.send({ received: true })
}
When I check my function logs, it just seems like it's not even firing / reaching my API at all - there's no logs.
Does anyone have any suggestions?
The problem is the default domain redirect in Vercel.
The recommended way is to redirect to www, so this is the format you should use:
Wrong: https://[YOUR_DOMAIN].com/api/endpoint
Right: https://www.[YOUR_DOMAIN].com/api/endpoint
Cheers
As the 308 error indicates, it looks like your server is receiving the webhook, but attempting to redirect it to another URL. It's possible that it's even the same URL, but over HTTPS.
Stripe can't follow redirects so this is a misconfiguration on your server's end. You have to give the exact URL for where your server expects to receive webhooks.
I am using express as a proxy server between a webapp and a remote backend service.
When piping responses through express, the response times are extremely slow.
Example (all services run locally on the same machine, tested with Postman, also running locally)
:8081 is the backend service, :4000 is the express proxy service
Fetching localhost:8081/api/assets/1 takes about 50ms. Absolutley fine.
But fetching localhost:4000/assets/1 takes 5 seconds
The code itself (to me) doesn't seem to indicate why this would take this much longer:
export const proxyApiCall = async (req: Request, res: Response, fullPath: string) => {
try {
const response = await backend.fetch(fullPath); // node-fetch with some additional headers
["content-type", "content-length", "last-modified", "cache-control"].forEach((name) => {
const value = response.headers.get(name);
if (value) {
res.setHeader(name, value);
}
});
res.status(response.status);
response.body.pipe(res);
} catch (err) {
LOG.error(err);
res.sendStatus(500);
}
};
I am using aws serverless mongodb template which works fine with mongodb queries and other local processing
I want make http request to get some data for that i tried. http/http/axios/request
But it just returns me following timeout error
{
"message": "Endpoint request timed out"
}
Following is my last tried code.
const util = require('../../lib/util')
// const UserModel = require('../../schema/User');
const fetch = require("node-fetch");
const url = "https://jsonplaceholder.typicode.com/posts/1";
module.exports = async (event) => {
try {
const response = await fetch(url);
const json = await response.json();
console.log(json);
return util.bind(json)
} catch (error) {
return util.bind(error)
}
}
Similarly API sdk's like paypal and razorpay also become unresponsive wile using.
is this problem with aws settings or nodejs code?
Thanks in advance.
Above code works fine on serverless offline
As per AWS all the lambdas has only incoming connection. lambda can not call any http for us. for that we need to have NAT Gateway.
using NAT Gateway your lambda/serverless will get internet access and it can make outgoing http calls.
Full error message: connect ECONNREFUSED 127.0.0.1:30561 at TCPConnectWrap.afterConnect
The axios request is running in a Node.js environment (Next.js), which is where the error occurs, strangely the axios request works perfectly fine when it is being run in the browser.
My component (running in Node.js) that calls axios:
import axios from 'axios'
import Router from 'next/router'
import React, { Component } from 'react'
import { initializeStore } from '~/reducers'
import { authenticate } from '~/actions/auth'
import { getCookieByName } from '~/helpers/cookie'
const isServer = typeof window === 'undefined'
const __NEXT_REDUX_STORE__ = '__NEXT_REDUX_STORE__'
function getOrCreateStore(initialState) {
// Always make a new store if server, otherwise state is shared between requests
if (isServer) {
return initializeStore(initialState)
}
// Create store if unavailable on the client and set it on the window object
if (!window[__NEXT_REDUX_STORE__]) {
window[__NEXT_REDUX_STORE__] = initializeStore(initialState)
}
return window[__NEXT_REDUX_STORE__]
}
export default App => {
return class AppWithRedux extends Component {
static async getInitialProps(appContext) {
const reduxStore = getOrCreateStore()
appContext.ctx.reduxStore = reduxStore
let appProps = {}
if (typeof App.getInitialProps === 'function') {
appProps = await App.getInitialProps(appContext)
}
const JWT = (isServer ? getCookieByName('JWT', appContext.ctx.req.headers.cookie) : getCookieByName('JWT', document.cookie))
const pathname = appContext.ctx.pathname
//set axios baseURL
axios.defaults.baseURL = (isServer ? `${appContext.ctx.req.headers['x-forwarded-proto']}://${appContext.ctx.req.headers.host}` : window.location.origin)
//if user has a JWT
if(JWT){
axios.defaults.headers.common['Authorization'] = `Bearer ${JWT}`
//get user from API layer
reduxStore.dispatch(authenticate())
}
return {
...appProps,
initialReduxState: reduxStore.getState()
}
}
constructor(props) {
super(props)
this.reduxStore = getOrCreateStore(props.initialReduxState)
}
render() {
return <App {...this.props} reduxStore={this.reduxStore} />
}
}
}
Specifically reduxStore.dispatch(authenticate())
And my actual axios call (using redux thunk), looking at the authenticate method:
import axios from 'axios'
import { setCookieByName } from '~/helpers/cookie'
const BASE_URL = '/api/auth'
export const TYPE_REGISTER = 'TYPE_REGISTER'
export const TYPE_AUTHENTICATE = 'TYPE_AUTHENTICATE'
export const register = values => (dispatch) => {
return axios.post(`${BASE_URL}/register`, values)
.then(function({data: {token, user}}){
setCookieByName('JWT', token, 365)
dispatch({
type: TYPE_REGISTER,
payload: user
})
})
}
export const authenticate = () => (dispatch) => {
return axios.post(`${BASE_URL}/me`)
.then(function({data: {user}}){
dispatch({
type: TYPE_AUTHENTICATE,
payload: user
})
})
.catch(function(err){
console.log(err)
dispatch({
type: TYPE_AUTHENTICATE,
payload: {}
})
})
}
I'm running my local Kubernetes cluster using Docker for Mac, and my Ingress controller is being accessed on http://kludge.info:30561. My domain is mapped from 127.0.0.1 kludge.info locally to allow the Ingress controller to hit the container. My theory is that when I send a request to http://kludge.info:30561/api/auth/me for example, the docker container running the Node.js app thinks it is a request to localhost (inside the container), and results in a connection error. Please note that the Node.js app inside the container is running on http://localhost:8080. Basically I'm running localhost on my machine, and localhost inside the Node instance. How could I send a request outside to http://kludge.info:30561/ where the Ingress controller is running.
I've also configured the baseURLin axios, but it does not solve the problem. My ingress controller has a path /api that will point to a PHP instance, so I need my Node.js axios call to hit that inside it's container. Any help would be much appreciated.
When I ran my K8 cluster on Minikube I did not have this problem, however minikube does provide you with the IP of the VM, while Docker for Desktop uses localhost directly on your machine.
If I understand you correctly I see that you open a socket on lcoalhost(127.0.0.1) so it is only accessible locally. If you want it to be accessible from outside you need to bind it to 0.0.0.0 meaning "all interfaces".
Listening on 0.0.0.0 means listening from anywhere with network access to this computer. For example, from this very computer, from local network or from the Internet. And listening on 127.0.0.1 means from this computer only.
Please let me know if that helped. Or if I have misunderstood you.
I'm building an electron app and need to call APIs where the API provider has not enabled CORS. The typically proposed solution is to use a reverse proxy which is trivial to do when running locally by using node and cors-anywhere like this:
let port = (process.argv.length > 2) ? parseInt (process.argv[2]) : 8080;
require ('cors-anywhere').createServer ().listen (port, 'localhost');
The app can then be configured to proxy all requests through the reverse proxy on localhost:8080.
So, my questions are:
Is it possible to use node and cors-anywhere in an electron app to create a reverse proxy? I don't want to force the app to make calls to a remote server.
Is there a better or standard way of doing this in an Electron app? I'm assuming I'm not the first to run into CORS issues. :)
Just overide header before send request using webRequest.onBeforeSendHeaders
const filter = {
urls: ['*://*.google.com/*']
};
const session = electron.remote.session
session.defaultSession.webRequest.onBeforeSendHeaders(filter, (details, callback) => {
details.requestHeaders['Origin'] = null;
details.headers['Origin'] = null;
callback({ requestHeaders: details.requestHeaders })
});
put these codes in renderer process
In my application, it wasn't sufficient to remove the Origin header (by setting it to null) in the request. The server I was passing the request to always provided the Access-Control-Allow-Origin header in the response, regardless of it the Origin header is present in the request. So the embedded instance of Chrome did not like that the ACAO header did not match its understanding of the origin.
Instead, I had to change the Origin header on the request and then restore it on the Access-Control-Allow-Origin header on the response.
app.on('ready', () => {
// Modify the origin for all requests to the following urls.
const filter = {
urls: ['http://example.com/*']
};
session.defaultSession.webRequest.onBeforeSendHeaders(
filter,
(details, callback) => {
console.log(details);
details.requestHeaders['Origin'] = 'http://example.com';
callback({ requestHeaders: details.requestHeaders });
}
);
session.defaultSession.webRequest.onHeadersReceived(
filter,
(details, callback) => {
console.log(details);
details.responseHeaders['Access-Control-Allow-Origin'] = [
'capacitor-electron://-'
];
callback({ responseHeaders: details.responseHeaders });
}
);
myCapacitorApp.init();
});
Try this if you are running web apps in localhost
const filter = {
urls: ['http://example.com/*'] // Remote API URS for which you are getting CORS error
}
browserWindow.webContents.session.webRequest.onBeforeSendHeaders(
filter,
(details, callback) => {
details.requestHeaders.Origin = `http://example.com/*`
callback({ requestHeaders: details.requestHeaders })
}
)
browserWindow.webContents.session.webRequest.onHeadersReceived(
filter,
(details, callback) => {
details.responseHeaders['access-control-allow-origin'] = [
'capacitor-electron://-',
'http://localhost:3000' // URL your local electron app hosted
]
callback({ responseHeaders: details.responseHeaders })
}
)
Just had this issue today API calls with axios inside a React app bundled in Electron is returning 400
From what I can see Electron calls act as normal calls to the API urls meaning they are not affected by CORS.
Now when you wrap your calls with a CORS proxy and make a regular call to the proxy, it should error with a 400 error because it's not a CORS call.
This thread explains why cors-anywhere responds like that => https://github.com/Rob--W/cors-anywhere/issues/39
I actually removed my CORS proxies from the app before the Electron build. I still need the CORS proxy for development since I'm testing in the browser.
Hope this helps.
You can have the main process, the NodeJS server running Electron, send the request. This avoids CORS because this is a server-to-server request. You can send an event from the frontend (the render process) to the main process using IPC. In the main process you can listen to this event, send the HTTP request, and return a promise to the frontend.
In main.js (the script where the Electron window is created):
import { app, protocol, BrowserWindow, ipcMain } from ‘electron’
import axios from 'axios'
ipcMain.handle('auth', async (event, ...args) => {
console.log('main: auth', event, args) const result = await axios.post(
'https://api.com/auth',
{
username: args[0].username,
password: args[0].password,
auth_type: args[1],
},
) console.log('main: auth result', result)
console.log('main: auth result.data', result.data) return result.data
})
In your frontend JS:
import { ipcRenderer } from 'electron'
sendAuthRequestUsingIpc() {
return ipcRenderer.invoke('auth',
{
username: AuthService.username,
password: AuthService.password,
},
'password',
).then((data) => {
AuthService.AUTH_TOKEN = data['access_token']
return true
}).catch((resp) => console.warn(resp))
}
I wrote an article that goes into more depth here.
While I have struggled a while with the existing answers I will provide here the solution that finally worked for me, assuming that you are on the main process.
Here are the steps involved:
You need to have access to the session object which can be obtained by one of two ways:
A) via the global session.defaultSession which is available after the app is ready.
const { session } = require('electron');
const curSession = session.defaultSession;
B) The other method is via the session on the BrowserWindow, this assumes that the windnows is already created.
win = new BrowserWindow({});
const curSession = win.webContents.session;
Once you have the session object you set the response header to the site you are sending the request from.
For example, let's say your electron BrowserWindow is loaded from http://localhost:3000 and you are making a request to example.com, here would be some sample code:
const { app, BrowserWindow, session } = require('electron');
app.whenReady().then(_ => {
// If using method B for the session you should first construct the BrowserWindow
const filter = { urls: ['*://*.example.com/*'] };
session.defaultSession.webRequest.onHeadersReceived(filter, (details, callback) => {
details.responseHeaders['Access-Control-Allow-Origin'] = [ 'http://localhost:3000' ];
callback({ responseHeaders: details.responseHeaders });
}
// Construct the BrowserWindow if haven't done so yet...
});
Have you tried using fetch()
Check how to use fetch to make a no-cors request here
https://developers.google.com/web/updates/2015/03/introduction-to-fetch?hl=en