I am trying to create a SocketIO solution with NextJS as below:
folder: api/socket.js
import { Server } from "socket.io";
const ioHandler = (req, res) => {
if (!res.socket.server.io) {
console.log("*First use, starting socket.io");
const io = new Server(res.socket.server);
io.on("connection", (socket) => {
console.log("Connected socket.io");
socket.broadcast.emit("a user connected");
socket.on("hello", (msg) => {
socket.emit("hello", "world!");
});
});
res.socket.server.io = io;
} else {
console.log("socket.io already running");
}
res.end();
};
export const config = {
api: {
bodyParser: false,
},
};
export default ioHandler;
folder: api/test.js
import io from "socket.io-client";
fetch("http://localhost:3000/api/socket");
const socket = io();
console.log(socket.connection);
socket.on("connect", () => {
console.log("connected");
});
But when I run api/test.js the SocketIO is not connected as below:
Socket {
connected: false,
receiveBuffer: [],
sendBuffer: [],
ids: 0,
acks: {},
flags: {},
io: Manager {
nsps: { '//undefined//undefined': [Circular *1] },
subs: [
[Function: subDestroy],
[Function: subDestroy],
[Function: subDestroy]
],
opts: {
path: '/socket.io',
hostname: 'undefined',
secure: false,
port: '80'
},
setTimeoutFn: [Function: bound setTimeout],
clearTimeoutFn: [Function: bound clearTimeout],
_reconnection: true,
_reconnectionAttempts: Infinity,
_reconnectionDelay: 1000,
_reconnectionDelayMax: 5000,
_randomizationFactor: 0.5,
backoff: Backoff {
ms: 1000,
max: 5000,
factor: 2,
jitter: 0.5,
attempts: 0
},
_timeout: 20000,
_readyState: 'opening',
uri: 'undefined//undefined//undefined',
encoder: Encoder { replacer: undefined },
decoder: Decoder { reviver: undefined },
_autoConnect: true,
engine: Socket {
setTimeoutFn: [Function: bound setTimeout],
clearTimeoutFn: [Function: bound clearTimeout],
secure: false,
hostname: 'undefined',
port: '80',
transports: [Array],
readyState: 'opening',
writeBuffer: [],
prevBufferLen: 0,
opts: [Object],
id: null,
upgrades: null,
pingInterval: null,
pingTimeout: null,
pingTimeoutTimer: null,
transport: [Polling],
_callbacks: [Object]
},
skipReconnect: false,
_callbacks: {
'$open': [Array],
'$packet': [Array],
'$error': [Array],
'$close': [Array]
}
},
nsp: '//undefined//undefined',
subs: [
[Function: subDestroy],
[Function: subDestroy],
[Function: subDestroy],
[Function: subDestroy]
]
}
Any suggestions?
According to documentation socket server options here socket.io v4
you need to specify a path same as client path
in your case
const io = new Server(res.socket.server, {path:'/api/socket'});
I have Next JS Application already hosted in VPS and data fetching using GetStaticProps and GetStaticPaths, then this application will consume REST Api from my subdomain with same VPS.
Next JS Application : http://zeffry.my.id
Rest API http://admin.zeffry.my.id/api
When i running npm run build on VPS, I get an error which indicates it is related to getStaticPaths.
zeffry#zeffryportofolio:/var/www/zeffry-reynando$ npm run build
> zeffry-reynando#0.1.0 build
> next build
info - Loaded env from /var/www/zeffry-reynando/.env
info - SWC minify release candidate enabled. https://nextjs.link/swcmin
info - Linting and checking validity of types
info - Creating an optimized production build
info - Compiled successfully
info - Collecting page data ..[AxiosError: Request failed with status code 400] {
code: 'ERR_BAD_REQUEST',
config: {
transitional: {
silentJSONParsing: true,
forcedJSONParsing: true,
clarifyTimeoutError: false
},
adapter: [Function: httpAdapter],
transformRequest: [ [Function: transformRequest] ],
transformResponse: [ [Function: transformResponse] ],
timeout: 0,
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
maxContentLength: -1,
maxBodyLength: -1,
env: { FormData: [Function] },
validateStatus: [Function: validateStatus],
headers: {
Accept: 'application/json, text/plain, */*',
'User-Agent': 'axios/0.27.2'
},
method: 'get',
url: "'http://admin.zeffry.my.id/api';/portfolio",
data: undefined
},
request: <ref *1> ClientRequest {
_events: [Object: null prototype] {
abort: [Function (anonymous)],
aborted: [Function (anonymous)],
connect: [Function (anonymous)],
error: [Function (anonymous)],
socket: [Function (anonymous)],
timeout: [Function (anonymous)],
prefinish: [Function: requestOnPrefinish]
},
_eventsCount: 7,
_maxListeners: undefined,
outputData: [],
outputSize: 0,
writable: true,
destroyed: false,
_last: true,
chunkedEncoding: false,
shouldKeepAlive: false,
maxRequestsOnConnectionReached: false,
_defaultKeepAlive: true,
useChunkedEncodingByDefault: false,
sendDate: false,
_removedConnection: false,
_removedContLen: false,
_removedTE: false,
_contentLength: 0,
_hasBody: true,
_trailer: '',
finished: true,
_headerSent: true,
_closed: false,
socket: Socket {
connecting: false,
_hadError: false,
_parent: null,
_host: 'localhost',
_readableState: [ReadableState],
_events: [Object: null prototype],
_eventsCount: 7,
_maxListeners: undefined,
_writableState: [WritableState],
allowHalfOpen: false,
_sockname: null,
_pendingData: null,
_pendingEncoding: '',
server: null,
_server: null,
parser: null,
_httpMessage: [Circular *1],
[Symbol(async_id_symbol)]: 13,
[Symbol(kHandle)]: [TCP],
[Symbol(lastWriteQueueSize)]: 0,
[Symbol(timeout)]: null,
[Symbol(kBuffer)]: null,
[Symbol(kBufferCb)]: null,
[Symbol(kBufferGen)]: null,
[Symbol(kCapture)]: false,
[Symbol(kSetNoDelay)]: false,
[Symbol(kSetKeepAlive)]: true,
[Symbol(kSetKeepAliveInitialDelay)]: 60,
[Symbol(kBytesRead)]: 0,
[Symbol(kBytesWritten)]: 0,
[Symbol(RequestTimeout)]: undefined
},
_header: 'GET %27http://admin.zeffry.my.id/api%27;/portfolio HTTP/1.1\r\n' +
'Accept: application/json, text/plain, */*\r\n' +
'User-Agent: axios/0.27.2\r\n' +
'Host: localhost\r\n' +
'Connection: close\r\n' +
'\r\n',
_keepAliveTimeout: 0,
_onPendingData: [Function: nop],
agent: Agent {
_events: [Object: null prototype],
_eventsCount: 2,
_maxListeners: undefined,
defaultPort: 80,
protocol: 'http:',
options: [Object: null prototype],
requests: [Object: null prototype] {},
sockets: [Object: null prototype],
freeSockets: [Object: null prototype] {},
keepAliveMsecs: 1000,
keepAlive: false,
maxSockets: Infinity,
maxFreeSockets: 256,
scheduling: 'lifo',
maxTotalSockets: Infinity,
totalSocketCount: 1,
[Symbol(kCapture)]: false
},
socketPath: undefined,
method: 'GET',
maxHeaderSize: undefined,
insecureHTTPParser: undefined,
path: '%27http://admin.zeffry.my.id/api%27;/portfolio',
_ended: true,
res: IncomingMessage {
_readableState: [ReadableState],
_events: [Object: null prototype],
_eventsCount: 4,
_maxListeners: undefined,
socket: [Socket],
httpVersionMajor: 1,
httpVersionMinor: 1,
httpVersion: '1.1',
complete: true,
rawHeaders: [Array],
rawTrailers: [],
aborted: false,
upgrade: false,
url: '',
method: null,
statusCode: 400,
statusMessage: 'Bad Request',
client: [Socket],
_consuming: false,
_dumped: false,
req: [Circular *1],
responseUrl: '%27http://admin.zeffry.my.id/api%27;/portfolio',
redirects: [],
[Symbol(kCapture)]: false,
[Symbol(kHeaders)]: [Object],
[Symbol(kHeadersCount)]: 10,
[Symbol(kTrailers)]: null,
[Symbol(kTrailersCount)]: 0,
[Symbol(RequestTimeout)]: undefined
},
aborted: false,
timeoutCb: null,
upgradeOrConnect: false,
parser: null,
maxHeadersCount: null,
reusedSocket: false,
host: 'localhost',
protocol: 'http:',
_redirectable: Writable {
_writableState: [WritableState],
_events: [Object: null prototype],
_eventsCount: 3,
_maxListeners: undefined,
_options: [Object],
_ended: true,
_ending: true,
_redirectCount: 0,
_redirects: [],
_requestBodyLength: 0,
_requestBodyBuffers: [],
_onNativeResponse: [Function (anonymous)],
_currentRequest: [Circular *1],
_currentUrl: '%27http://admin.zeffry.my.id/api%27;/portfolio',
[Symbol(kCapture)]: false
},
[Symbol(kCapture)]: false,
[Symbol(kNeedDrain)]: false,
[Symbol(corked)]: 0,
[Symbol(kOutHeaders)]: [Object: null prototype] {
accept: [Array],
'user-agent': [Array],
host: [Array]
},
[Symbol(kUniqueHeaders)]: null
},
response: {
status: 400,
statusText: 'Bad Request',
headers: {
server: 'nginx/1.18.0 (Ubuntu)',
date: 'Fri, 02 Sep 2022 11:48:55 GMT',
'content-type': 'text/html',
'content-length': '166',
connection: 'close'
},
config: {
transitional: [Object],
adapter: [Function: httpAdapter],
transformRequest: [Array],
transformResponse: [Array],
timeout: 0,
xsrfCookieName: 'XSRF-TOKEN',
xsrfHeaderName: 'X-XSRF-TOKEN',
maxContentLength: -1,
maxBodyLength: -1,
env: [Object],
validateStatus: [Function: validateStatus],
headers: [Object],
method: 'get',
url: "'http://admin.zeffry.my.id/api';/portfolio",
data: undefined
},
request: <ref *1> ClientRequest {
_events: [Object: null prototype],
_eventsCount: 7,
_maxListeners: undefined,
outputData: [],
outputSize: 0,
writable: true,
destroyed: false,
_last: true,
chunkedEncoding: false,
shouldKeepAlive: false,
maxRequestsOnConnectionReached: false,
_defaultKeepAlive: true,
useChunkedEncodingByDefault: false,
sendDate: false,
_removedConnection: false,
_removedContLen: false,
_removedTE: false,
_contentLength: 0,
_hasBody: true,
_trailer: '',
finished: true,
_headerSent: true,
_closed: false,
socket: [Socket],
_header: 'GET %27http://admin.zeffry.my.id/api%27;/portfolio HTTP/1.1\r\n' +
'Accept: application/json, text/plain, */*\r\n' +
'User-Agent: axios/0.27.2\r\n' +
'Host: localhost\r\n' +
'Connection: close\r\n' +
'\r\n',
_keepAliveTimeout: 0,
_onPendingData: [Function: nop],
agent: [Agent],
socketPath: undefined,
method: 'GET',
maxHeaderSize: undefined,
insecureHTTPParser: undefined,
path: '%27http://admin.zeffry.my.id/api%27;/portfolio',
_ended: true,
res: [IncomingMessage],
aborted: false,
timeoutCb: null,
upgradeOrConnect: false,
parser: null,
maxHeadersCount: null,
reusedSocket: false,
host: 'localhost',
protocol: 'http:',
_redirectable: [Writable],
[Symbol(kCapture)]: false,
[Symbol(kNeedDrain)]: false,
[Symbol(corked)]: 0,
[Symbol(kOutHeaders)]: [Object: null prototype],
[Symbol(kUniqueHeaders)]: null
},
data: '<html>\r\n' +
'<head><title>400 Bad Request</title></head>\r\n' +
'<body>\r\n' +
'<center><h1>400 Bad Request</h1></center>\r\n' +
'<hr><center>nginx/1.18.0 (Ubuntu)</center>\r\n' +
'</body>\r\n' +
'</html>\r\n'
}
}
> Build error occurred
Error: Failed to collect page data for /portfolio/[slug]
at /var/www/zeffry-reynando/node_modules/next/dist/build/utils.js:743:15
at processTicksAndRejections (node:internal/process/task_queues:96:5) {
type: 'Error'
}
This line indicate the rror :
export const getStaticProps: GetStaticProps = async (context) => {
try {
const { slug } = context.params as IParams;
const url =
process.env["NODE_ENV"] == "development"
? process.env["BASE_API_LOCALHOST_URL"]
: process.env["BASE_API_URL"];
const portfolio = await axios.get(`${url}/portfolio/${slug}`);
if (!portfolio.data.data) throw "Data tidak ditemukan";
const data: PortfolioDetailInterface = portfolio.data.data;
const props = {
portfolio: data,
};
return {
props: props,
};
} catch (error) {
return {
notFound: true,
};
}
};
export const getStaticPaths: GetStaticPaths = async (context) => {
const url =
process.env["NODE_ENV"] == "development"
? process.env["BASE_API_LOCALHOST_URL"]
: process.env["BASE_API_URL"];
const portfolio = await axios.get(`${url}/portfolio`);
const arrPortfolio: PortfolioInterface[] = portfolio.data.data;
const slug = arrPortfolio.map(function (val) {
return {
params: {
slug: val.title_slug,
},
};
});
return {
paths: slug,
fallback: "blocking",
};
};
export default PortfolioDetailPage;
I can confirm that when testing on my local machine, the application runs smoothly without any problems.
If you access this endpoint http://admin.zeffry.my.id/api/portfolio/amerta, response is
// 20220902190903
// http://admin.zeffry.my.id/api/portfolio/amerta
{
"success": true,
"data": {
"id": 1,
"type_application_id": 11,
"main_technology_id": 15,
"title": "Amerta",
"title_slug": "amerta",
"short_description": "amerta",
"full_description": "<p>amerta</p>",
"banner_image": "http://admin.zeffry.my.id/storage/images/portfolio/banner/6311b9c0e52cc1662106048.png",
"github_url": null,
"web_url": null,
"google_playstore_url": null,
"app_store_url": null,
"created_at": "2022-09-02T08:07:30.000000Z",
"updated_at": "2022-09-02T08:07:30.000000Z",
"created_by": null,
"updated_by": null,
"previewImages": [
{
"id": "c9a51e0b-4357-44a5-9b92-07f404050561",
"portfolio_id": 1,
"image": "http://admin.zeffry.my.id/storage/images/portfolio/preview/6311b9c2c9b281662106050.png"
}
],
"main_technology": {
"id": 15,
"name": "Flutter"
},
"type": {
"id": 11,
"name": "Mobile Apps"
},
"other_technology": [
{
"id": "faaf2db5-1c0c-4c05-8fa9-3da43fb4e2ce",
"portfolio_id": 1,
"technology_id": 15,
"technology": {
"id": 15,
"name": "Flutter"
}
}
],
"preview_images": [
{
"id": "c9a51e0b-4357-44a5-9b92-07f404050561",
"portfolio_id": 1,
"image": "http://admin.zeffry.my.id/storage/images/portfolio/preview/6311b9c2c9b281662106050.png"
}
]
}
}
Are there any settings for deploying missing?
I have a cors issue in my development with vue3 & vite, so I create a proxy config in my vite.config.js
import { defineConfig } from 'vite'
import vue from '#vitejs/plugin-vue'
import { resolve } from 'path'
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
'#': resolve(__dirname, 'src'),
},
},
server: {
proxy: {
"/api": {
target: "https://###.com",
changeOrigin: true,
secure: false,
rewrite: (path) => path.replace(/^\/api/, ""),
},
}
}
})
when I use in my app my method:
createPayment() {
const url = "/api/webhook/###";
let formData = new FormData();
formData.append("firstName", this.first_name);
formData.append("lastName", this.last_name);
formData.append("email", this.email);
formData.append("phone", this.phone);
formData.append("cardNumber", this.c_number);
formData.append("cardExpiration", this.c_EXP);
formData.append("cardCCV", this.c_CVC);
const request = new Request(url, {
method: "POST",
body: formData,
headers: {
accept: 'application/json',
contentType: "application/json;charset=UTF-8",
AccessControlAllowOrigin: '*'
},
});
fetch(request)
.then(result => console.log(result))
.catch(error => console.log('error', error));
},
The Post all ways send from localhost, I can't understand why?
I make the config for change '/api' to 'https://###.com' ?
My Log:
Response {type: 'basic', url: 'http://localhost:3000/api/webhook/####', redirected: false, status: 404, ok: false, …}
I am using RTK-Query, and Redux-toolkit for this app, and I created an api-slice with createApi, as per the docs.
When I run a request to the backend, I get a "FETCH_ERROR"; however, when I run the same request using Axios, I get the data correctly from the backend, which leads me to believe I have an error in my code. I am just not sure where exactly it is.
Here is the error:
Object {
"api": Object {
"config": Object {
"focused": true,
"keepUnusedDataFor": 60,
"middlewareRegistered": true,
"online": true,
"reducerPath": "api",
"refetchOnFocus": false,
"refetchOnMountOrArgChange": false,
"refetchOnReconnect": false,
},
"mutations": Object {},
"provided": Object {},
"queries": Object {
"test(undefined)": Object {
"endpointName": "test",
"error": Object {
"error": "TypeError: Network request failed",
"status": "FETCH_ERROR",
},
"requestId": "BWOuLpOxoDKTzlUYFLW4x",
"startedTimeStamp": 1643667104869,
"status": "rejected",
},
},
"subscriptions": Object {
"test(undefined)": Object {
"QJSCV641RznGWyudGWuMb": Object {
"pollingInterval": 0,
"refetchOnFocus": undefined,
"refetchOnReconnect": undefined,
},
},
},
},
"test": Object {
"data": Array [],
},
}
Here is the test slice:
import { createSlice } from "#reduxjs/toolkit";
const testSlice = createSlice({
name: "test",
initialState: {
data: [],
},
reducers: {
getData: (state) => {
state;
},
},
});
export const { getData } = testSlice.actions;
export default testSlice.reducer;
Here is the apiSlice:
import { createApi, fetchBaseQuery } from "#reduxjs/toolkit/query/react";
export const apiSice = createApi({
reducerPath: "test",
baseQuery: fetchBaseQuery({ baseUrl: process.env.REACT_APP_backend_url }),
endpoints: (builder) => ({
test: builder.query({
query: () => "/test",
}),
}),
});
export const { useTestQuery } = apiSice;
I solved it by changing the backend URL to my current ipv4 (for expo development, otherwise just your whatever your backend URL is) address in my .env file, then deleting cache, and restarting my app. In my case I was using expo so, expo r -c, and it worked.
I have a method that should return a response from another server. I use request-promise and put the URL in the options object.
As you can see in the code below, all is in good shape, but when I send the request, it returns 404 - resource not found.
When I change the request(options) method with request("https://api.quickpay.net/payments"), I get a positive answer from the server -- it tells me to add headers and so forth, which is positive.
public requestNewQuickpayPayment(order_id: String, currency : String, callback: Function) {
var options = {
method: 'POST',
uri: 'https://api.quickpay.net/payments',
form:{
order_id : "order123",
currency : "dkk"
},
headers: {
"Content-Type" : "application/json",
'Accept-Version': 'v10'
},
json: true
};
request(options).then((response:any)=>{
console.log(response);
return response;
}).catch((error:any)=>{
console.log(error);
return error;
}).finally(()=>{
console.log("done");
})
}
Something from the console
Request {
_events: [Object],
_eventsCount: 5,
_maxListeners: undefined,
method: 'POST',
uri: [Url],
transform2xxOnly: true,
headers: [Object],
readable: true,
writable: true,
explicitMethod: true,
_qs: [Querystring],
_auth: [Auth],
_oauth: [OAuth],
_multipart: [Multipart],
_redirect: [Redirect],
_tunnel: [Tunnel],
_rp_resolve: [Function],
_rp_reject: [Function],
_rp_promise: [Promise],
_rp_callbackOrig: undefined,
callback: [Function],
_rp_options: [Object],
setHeader: [Function],
hasHeader: [Function],
getHeader: [Function],
removeHeader: [Function],
localAddress: undefined,
pool: {},
dests: [],
__isRequestRequest: true,
_callback: [Function: RP$callback],
proxy: null,
tunnel: true,
setHost: true,
originalCookieHeader: undefined,
_disableCookies: true,
_jar: undefined,
port: 443,
host: 'api.quickpay.net',
body: 'order_id=asdasdasd¤cy=dkk',
path: '/payments',
_json: true,
httpModule: [Object],
agentClass: [Function],
agent: [Agent],
_started: true,
href: 'https://api.quickpay.net/payments',
req: [ClientRequest],
ntick: true,
response: [Circular],
originalHost: 'api.quickpay.net',
originalHostHeaderName: 'host',
responseContent: [Circular],
_destdata: true,
_ended: true,
_callbackCalled: true },
toJSON: [Function: responseToJSON],
caseless: Caseless { dict: [Object] },
body: '404 Not Found' } }
What is wrong here? The path to the ressource is checked many times - nothing is wrong there....
For api.quickpay.net, 404 Not Found does not mean the URI is not recognized, but indicating invalid request body. It has nothing to do with whether the URI is stated in options object, or stated as string parameter of request().
Here is a simple experiment. The code below would return "positive" result, warning missing headers ({"error":"Accept-Version http header is required"}), which indicates that the URI is "recognized":
request({
method: 'POST',
uri: 'https://api.quickpay.net/payments'
}, function(err, res, body) {
console.log(body);
});
However, after the missing Accept-Version header is added, we get 404 Not Found:
request({
method: 'POST',
uri: 'https://api.quickpay.net/payments',
headers: {
'Accept-Version': 'v10'
}
}, function(err, res, body) {
console.log(body);
});
Thus, in order to make the API call work, you need to make the HTTP request valid (following to the document).