Next.js getServerSideProps give 404 on production only - javascript

I have reproduced the problem to the simplest form:
let's start with the backend:
#models.py
from django.db import models
from django.template.defaultfilters import slugify # new
class Article(models.Model):
slug = models.SlugField(primary_key=True,unique=True)
title = models.CharField(max_length=200)
description = models.TextField()
def save(self,*args,**kwargs):
if not self.slug:
self.slug = slugify(self.title)
super().save(*args,**kwargs)
#views.py
from django.shortcuts import render
from rest_framework.viewsets import ModelViewSet
from rest_framework.response import Response
from app import models
from app import serializer
class ArticleView(ModelViewSet):
serializer_class = serializer.ArticleSerializer
def get_queryset(self):
return models.Article.objects.all()
def post(self,request):
data = serializer.ArticleSerializer(data=request.data)
if data.is_valid():
a = models.Article.objects.create(title=data['title'],description=data['description'])
a.save()
return Response("succes",status=200)
return Response("fail",status=400)
#serializer.py
from rest_framework import serializers
from app import models
class ArticleSerializer(serializers.ModelSerializer):
slug = serializers.SlugField(read_only=True)
class Meta:
fields = 'slug','title','description',
model = models.Article
#settings.py
ALLOWED_HOSTS = ['localhost','127.0.0.1']
ACCESS_CONTROL_ALLOW_ORIGIN = '*'
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_CREDENTIALS = True
ACCESS_CONTROL_ALLOW_CREDENTIALS = True
ACCESS_CONTROL_ALLOW_METHODS = '*'
ACCESS_CONTROL_ALLOW_HEADERS = '*'
# Application definition
INSTALLED_APPS = [
'app',
'rest_framework',
'corsheaders',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
"corsheaders.middleware.CorsMiddleware",
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
I have provided everything related to the backend
Now on next js side:
i got this (inside pages folder):
and the code is like this inside [slug].js
import axios from 'axios'
export async function getServerSideProps({params}){
try{
let res = await axios.get(`https://somehost.com/articles/${params.slug}/`)
let data = res.data
return {
props:{data:data}
}
}
catch(e){
return {
props:{}
}
}
}
export default function Component({data}){
if(data){
return<div>
<div>{data.title}</div>
<div>{data.description}</div>
</div>
}
}
i get this on production:
what is more annoying is that on network tab, there is no request being sent to the backend.
any idea?
EDIT: I am deploying on Cloudflare NOT VERCEL.

Related

NestJS - How to set 'Access-Control-Allow-Origin' Header for Response

I am trying to set the Response header in NestJS, but keep getting the following error:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://companyName.okta.com/app/companyName_imentorlocalhost_1/exk1hp5ht4vrEzqGg0h8/sso/saml?SAMLRequest=nVPLct... (Reason: CORS header ‘Access-Control-Allow-Origin’ missing).
I tried setting the header in the controller, but that didn't work:
auth.controller:
#UseGuards(SamlAuthGuard)
#Header('Access-Control-Allow-Origin', '*')
#Get('box-utility-service/auth/login')
login(#Request() req): any {}
#UseGuards(SamlAuthGuard)
#Header('Access-Control-Allow-Origin', '*')
#Post('imentor-service/login/callback')
oktaCallback (#Request() req, #Response() res: Response): any {
return this.authService.login(req);
}
Also tried setting the header in an interceptor. Didn't work either:
header.interceptor.ts:
#Injectable()
export class HeaderInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
return next.handle().pipe(
tap(() => {
const res = context.switchToHttp().getResponse();
res.setHeader('Access-Control-Allow-Origin', '*');
})
)
}
}
Here's my main.ts, where I enable CORS:
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.use(
session({
secret: 'my-secret',
resave: false,
saveUninitialized: false
}),
);
app.enableCors({
allowedHeaders: [ 'Accept', 'Accept-Version', 'Content-Type', 'Api-Version', 'Origin', 'X-Requested-With',
'Authorization' ],
origin: [ 'https://companyName.okta.com', 'http://localhost:4200', 'http://localhost' ],
credentials: true,
exposedHeaders: [ 'API-Token-Expiry' ]
});
app.useGlobalInterceptors(new HeaderInterceptor());
await app.listen(3000);
}
bootstrap();
And here is my saml-strategy.ts file, where I define the Passport strategy to be SAML:
import { Injectable } from '#nestjs/common';
import { PassportStrategy } from '#nestjs/passport';
import { AuthService } from './auth.service';
const nconf = require('nconf');
import { get } from 'lodash';
const SamlStrategy = require('passport-saml').Strategy;
import { UsersService } from '../users/users.service';
#Injectable()
export class Saml2Strategy extends PassportStrategy(SamlStrategy, 'saml') {
users = [];
constructor(
private authService: AuthService,
private usersService: UsersService
) {
super({
issuer: nconf.get('saml:issuer'),
path: nconf.get('saml:path'),
entryPoint: nconf.get('saml:entryPoint'),
cert: nconf.get('saml:cert')
});
}
async validate(payload: any) {
const oeid = payload.nameID;
let user;
if (oeid) {
try {
let userADData = await this.authService.validateUser(oeid);
userADData = get(userADData, 'data.data[0]');
if (userADData) {
user = await this.usersService.findOrCreate(userADData);
}
return user;
} catch (err) {
return err;
}
}
}
}
Any idea of what's going on? Thanks.
Turns out it was a problem with the way I was handling the OKTA login workflow. I was redirecting an XHR request (which OKTA didn't like, as it was missing the required header to do so), and was getting an error code.

Request not being processed

Im currently trying to learn more about Express and Express-Validator but currently facing the following issue: When I'm starting the server and using Postman do excess one of the endpoints the response is not completed. However, it seems like the Validation Chain is being processed but afterwards nothing happens. I have the following modules:
index.ts
import {config} from 'dotenv';
import App from './api/app';
import ControlAmbilight from './api/routes/controlAmbilight';
import AdjustLightning from './app/AdjustLightning';
const ENV_FILE = path.join(__dirname, '..', '.env');
config({path: ENV_FILE});
const PORT = process.env.port || process.env.PORT || 3000;
const ambient = new AdjustLightning();
const app = new App([
new ControlAmbilight(ambient),
], <number> PORT);
app.listen();
app.ts
import * as bodyParser from 'body-parser';
import pino from 'pino';
import expressPino from 'express-pino-logger';
import errorMiddleware from './middleware/errorMiddleware';
export default class App {
private logger: pino.Logger;
private expressLogger;
public app: express.Application;
public port: number;
constructor(controllers: any, port: number) {
this.app = express();
this.port = port;
this.logger = pino({level: process.env.LOG_LEVEL || 'info'});
this.expressLogger = expressPino({logger: this.logger});
this.initializeMiddlewares();
this.initializeControllers(controllers);
this.initializeErrorHandling();
}
private initializeMiddlewares() {
this.app.use(this.expressLogger);
this.app.use(bodyParser.json());
}
private initializeControllers(controllers: any) {
controllers.forEach((controller: any) => {
this.app.use('/', controller.router);
});
}
private initializeErrorHandling() {
this.app.use(errorMiddleware)
}
public listen() {
this.app.listen(this.port, () => {
this.logger.info(`Server running on ${this.port}`);
});
}
}
controlAmbilight.ts
import {Router, Request, Response, NextFunction} from 'express';
import {ValidationChain, check, validationResult} from 'express-validator';
import AdjustLightning from '../../app/AdjustLightning';
// eslint-disable-next-line require-jsdoc
export default class ControlAmbilight {
private ambient: AdjustLightning;
// eslint-disable-next-line new-cap
public router = Router();
public path = '/controlAmbilight';
// eslint-disable-next-line require-jsdoc
constructor(ambient: AdjustLightning) {
this.ambient = ambient;
this.initializeRoutes();
}
// eslint-disable-next-line require-jsdoc
public initializeRoutes() {
this.router.post(this.path, this.controlValidator, this.setAmbilight.bind(this));
}
private controlValidator = (): ValidationChain[] => [
check('on').notEmpty().withMessage('Field \'on\' is required'),
check('on').isBoolean().withMessage('Field \'on\' must be type boolean'),
];
// eslint-disable-next-line require-jsdoc
private setAmbilight(req: Request, res: Response): void {
const errors = validationResult(req);
if (!errors.isEmpty()) {
res.status(422).json({error: errors.array()});
} else {
const isOn = (req.body.on == 'true');
res.send(`The curent state is: ${this.ambient.getIsActive()}`);
}
}
}
I was hopping that someone could explain me what I'm missing here. It seems like I need to call express` next() middleware function, but I'm not sure where to implement it.
EDIT
As requested I'm adding the errorMiddleware:
import { NextFunction, Request, Response } from 'express';
import HttpException from '../exceptions/HttpException';
export default function errorMiddleware (error: HttpException,
request: Request, response: Response, next: NextFunction) {
const status = error.status || 500;
const message = error.message || 'Ups... This did not work :(';
response
.status(status)
.send({ status,
message });
}
And as an additional comment: When I'm adding the Validation Chain directly into the post method within controlAmbilight.ts like that:
public initializeRoutes() {
this.router.post(this.path, [
check('on').notEmpty().withMessage('Field \'on\' is required'),
check('on').isBoolean().withMessage('Field \'on\' must be type boolean'),
], this.setAmbilight.bind(this));
}
It is working as expected.

Angular 9 SSR ReferenceError: stripe.elements is not defined

for my project Angular 9 I must install Server-side rendering (SSR), I followed official tutorial https://angular.io/guide/universal. At the beginning I have the problem with the window is not define. So I decided to install SSR with domino and I followed this tutorial enter link description here , but I have a problem when the program build my project : elements is not define. (const elements = stripe.elements() Cannot read property elements of undefined).
Below my server.ts code
import 'zone.js/dist/zone-node';
import { ngExpressEngine } from '#nguniversal/express-engine';
import * as express from 'express';
import { join } from 'path';
import { APP_BASE_HREF } from '#angular/common';
import { existsSync } from 'fs';
import * as core from 'express-serve-static-core';
const domino = require('domino');
const fs = require('fs');
const path = require('path');
// Use the browser index.html as template for the mock window
const template = fs
.readFileSync(path.join(join(process.cwd(), 'dist/captn-boat-angular/browser'), 'index.html'))
.toString();
// Shim for the global window and document objects.
const window = domino.createWindow(template);
global['window'] = window;
global['document'] = window.document;
global ['navigator']=window.navigator;
global ['screen']=window.screen;
global['Event'] = null;
global['window'] = window;
global['document'] = window.document;
global['branch'] = null;
global['object'] = window.object;
global['localStorage'] = window.localStorage;
global['navigator'] = window.navigator ;
global['elements']=window.elements;
global['elements']=null;
global['Event'] = null;
global['KeyboardEvent'] = null;
global['stripe']=window.stripe;
window.screen = { deviceXDPI: 0, logicalXDPI: 0 };
global['MouseEvent'] = window.MouseEvent;
declare interface Window {
Stripe: any; // Or you can define a type for that in this file as well
stripe:null;
elements:null;
}
import { AppServerModule } from './src/main.server';
// The Express app is exported so that it can be used by serverless Functions.
export function app(): core.Express {
const server = express();
const distFolder = join(process.cwd(), 'dist/captn-boat-angular/browser');
const indexHtml = existsSync(join(distFolder, 'index.original.html')) ? 'index.original.html' : 'index';
// Our Universal express-engine (found # https://github.com/angular/universal/tree/master/modules/express-engine)
server.engine('html', ngExpressEngine({
bootstrap: AppServerModule,
}));
server.set('view engine', 'html');
server.set('views', distFolder);
// Example Express Rest API endpoints
// server.get('/api/**', (req, res) => { });
// Serve static files from /browser
server.get('*.*', express.static(distFolder, {
maxAge: '1y'
}));
// All regular routes use the Universal engine
server.get('*', (req, res) => {
res.render(indexHtml, { req, providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }] });
});
return server;
}
function run() {
const port = process.env.PORT || 4000;
// Start up the Node server
const server = app();
server.listen(port, () => {
console.log(`Node Express server listening on http://localhost:${port}`);
});
}
// Webpack will replace 'require' with '__webpack_require__'
// '__non_webpack_require__' is a proxy to Node 'require'
// The below code is to ensure that the server is run only when not requiring the bundle.
declare const __non_webpack_require__: NodeRequire;
const mainModule = __non_webpack_require__.main;
const moduleFilename = mainModule && mainModule.filename || '';
if (moduleFilename === __filename || moduleFilename.includes('iisnode')) {
run();
}
export * from './src/main.server';
And then the error : elements of undefined
Thank you for your answer.
Do you use stripe in every place on your application ? I'd use it in the payment section of the related module and would connect it to lazy loading. Thus you could use one of the importer of stripe ?
like here :ngx-stripe installation

express.session undefined in typescript

I am very new to typescript/javascript, I am trying to build backend rest apis with session
following is app.ts file
import express from "express";
import { applyMiddleware, applyRoutes } from "./utils";
import routes from "./services";
const app = express();
var ses= {
secret: "secret_session",
resave: true,
saveUninitialized: true,
cookie: { maxAge: 3600000,secure: false, httpOnly: true
}
if (app.get('env') === 'production') {
app.set('trust proxy', 1)
ses.cookie.secure = true
}
app.use(session(ses));
applyRoutes(routes, app);
I have started the server and applied the middlewares for error handling but those are not related to question in my opinion so I'm not adding code for it. Following is my routes.ts code where I'm trying to set the session.
import { Request, Response } from "express";
import { getAll, getByKeyword, addNewProduct } from "./productControllers";
{
path: "/api/v1/getAllProducts",
method: "get",
handler: [
(req: Request, res: Response) => {
getAll()
.then((row: any) => {
var sess = req.session;
sess.views = 1;
res.status(200).json({ data: row });
})
.catch(err => {
res.json({
message: err
});
});
}
]
}
I'm getting error at sess.views = 1;
I have tried the suggested questions before asking it, none of them were of any help to me.
EDIT:
I have created an index.ts
import searchRoutes from "./products/routes";
export default [...searchRoutes];
I have another util class
export const applyRoutes = (routes: Route[], router: Router) => {
for (const route of routes) {
const { method, path, handler } = route;
(router as any)[method](path, handler);
}
}
You are using an interface which is Request for express.js. But it doesn't have type definition for session. So typescript throws a compile error. To solve it you need to define session type under Request interface.
You could define a session.d.ts file under your project. And create required types & interfaces. Like:
declare global {
namespace Express {
interface Request {
session?: Session;
sessionID?: string;
}
}
}
interface Session{
mySessionVarible:string
}
But the good thing is we have DefinitilyTyped project which you can find many type definitions. This needs to solve your compile problem.
npm install --save-dev #types/express-session
And don't forget to change your import for Request.
import { Request, Response } from "#types/express-session";

How to send token in cookie, from server request angular universal?

I need to send from my server side to API in request headers "Cookie: token"
In angular universal, for servers Http request methods I use axios. when I try to change headers using Interceptor I have an error "Refused to set unsafe header 'Cookie'" if I send a static cookie like third arguments of axios post all work fine but I have some troubles to dynamically insert token there.
request.servise.ts
import { RequestBody } from './models/request-body.model';
import axios from 'axios';
import {AxiosInstance} from 'axios';
export class Request {
http: AxiosInstance = axios;
constructor() {}
async test(): Promise<any> {
const params = {
param1: 1,
param2: 2,
param3: 3,
}
try {
return this.basicRequest('https://some-request.url', params);
} catch (e) {
console.error('Unknown exception: ', e);
return null;
}
}
private basicRequest(url, params) {
const request = new RequestBody('2.0', 'someMethod', Math.floor(Math.random() * (9999999 - 1000000)) + 1000000, params);
return this.http.post(url, request);
}
}
projects.ts (sever router controller)
import {Router} from 'express';
import {Request} from '../../shared/request.service';
const router: Router = Router();
router.get('/test', async function(req, res, next){
const request = new Request();
try {
const projects = (await request.test()).data.result.records;
res.json(projects);
} catch (e) {
console.error(e);
}
});
export const ProjectsController: Router = router;
By default, angular universal does not transfert cookieswhen using HttpClient. So, you need to do it manually, but you'll get the error you mentionned.
A possible workaround, suggested in that universal github issue, is to bypass xhr2's default security behaviour for unsafe headers
server.ts
import * as xhr2 from 'xhr2';
xhr2.prototype._restrictedHeaders = {};

Categories

Resources