1

I’m developing a translation API for a Chrome extension using Express and Netlify Functions. However, I’m encountering issues with CORS when making requests from the browser. The preflight OPTIONS request fails, and I’m stuck trying to resolve the issue.

Here is my server

import express from "express";
import cors from "cors";
import { getTranslation } from "./translator.js";
import serverless from "serverless-http";
const app = express();
const router = express.Router();
app.use(express.json());
app.use(
 cors({
 origin: "*",
 methods: ["POST", "OPTIONS"],
 allowedHeaders: ["Content-Type"],
 })
);
router.options("/translate", cors(), (req, res) => {
 res.sendStatus(204);
});
router.get("/", (req, res) => {
 res.send("This is a translator app for DragWords chrome extension.");
});
router.post("/translate", async (req, res) => {
 const body = req.body;
 const { sourceText, targetLang } = body;
 try {
 const { translatedText } = await getTranslation({
 text: sourceText,
 targetLang: targetLang,
 });
 res.status(200).json({ translation: translatedText, serverError: null });
 } catch (err) {
 console.error(err);
 res.status(500).json({ translation: null, serverError: err });
 }
});
app.use("/.netlify/functions/api", router);
export const handler = serverless(app);

and here is my netlify.toml

[build]
 publish = "dist"
 functions = "functions"
[context.production.environment]
 DEEPL_API_KEY = "my api key"
[[headers]]
 for = "/.netlify/functions/api/*"
 [headers.values]
 Access-Control-Allow-Origin = "*"
 Access-Control-Allow-Methods = "POST, OPTIONS"
 Access-Control-Allow-Headers = "Content-Type"

I ran this server on my localhost:8888 and I sent a request to the server from "https://ricki-lee.medium.com" but there is still a CORS error.

https://ricki-lee.medium.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

here is my client code in the content.js file which gets translation from the server

async function getTranslation(sourceText) {
 try {
 const defaultTargetLang = await getDefaultTargetlang();
 const response = await fetch("http://localhost:8888/translate", {
 method: "POST",
 headers: {
 "Content-Type": "application/json",
 },
 body: JSON.stringify({
 sourceText: sourceText,
 targetLang: defaultTargetLang,
 }),
 });
 const { translation, serverError } = await response.json();
 if (serverError !== null) {
 throw new Error(serverError);
 }
 return translation;
 } catch (err) {
 console.error(err);
 return null;
 }
}

I set Access-Control-Allow-Origin = "*" but it seems it doesn't work

I also tested the OPTIONS request using curl, which returned the following error:

curl -X OPTIONS http://localhost:8888/translate -H "Origin: https://ricki-lee.medium.com"
Method Not Allowed

How can I configure my Express server or Netlify setup to handle the preflight OPTIONS request properly and resolve the CORS error?

asked Dec 27, 2024 at 3:57
0

1 Answer 1

0

There are three problems with your code.

Wrong service path

You have registered the router that handles the /translate request on the /.netlify/functions/api path, but you invoke it as http://localhost:8888/translate. Shouldn't that be http://localhost:8888/.netlify/functions/api/translate?

Incorrect CORS configuration

If you want to allow any origin, set origin: true, not origin: "*". But as jub0bs commented, this should be avoided and is clearly unnecessary in your case, because you use only one origin.

Also, you need not specify any special handling for OPTIONS, because the cors handles preflights automatically. So what you need is just:

app.use(
 cors({
 origin: "https://ricki-lee.medium.com",
 methods: ["POST"],
 allowedHeaders: ["Content-Type"],
 })
);

and no router.options("/translate", ...).

Private network access

The origin of your CORS request is in the public cloud whereas the URL that it calls is in your private network. In this situation, the preflight request contains

Access-Control-Request-Private-Network: true

and its response must contain

Access-Control-Allow-Private-Network: true

(see also https://developer.chrome.com/blog/private-network-access-preflight).

But the cors package does not set this response header. You can set it yourself with the following Node.js code:

app.use(
 cors({
 origin: "https://ricki-lee.medium.com",
 methods: ["POST"],
 allowedHeaders: ["Content-Type"],
 preflightContinue: true
 })
)
.options("*", function(req, res) {
 if (res.get("Access-Control-Allow-Origin"))
 res.set("Access-Control-Allow-Private-Network", "true");
 res.end();
});

Lastly, I do not understand why you need the [[headers]] configuration in netlify.toml. The CORS-relevant headers should already be set by the express.js app.

answered Dec 27, 2024 at 8:58
Sign up to request clarification or add additional context in comments.

3 Comments

Thank you for this comment :), but it still doesn't work..
You shouldn't encourage people to set origin to true. There's never a good reason to do that. In particular, you don't want to allow any origin in conjunction with private-network access; see the warning in developer.chrome.com/blog/private-network-access-preflight/….
Okay I will change it soon!

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.