【问题标题】:Node/Express server CORS issue with a different server portNode/Express 服务器 CORS 问题与不同的服务器端口
【发布时间】:2020-12-07 21:10:45
【问题描述】:

我有一个 node/graphql 服务器在 sitename.com:3333 上运行 我创建了另一台服务器,在 sitename.com:3334 上运行

我可以从 sitename.com 和 subdomain.sitename.com 向位于 sitename.com:3333 的服务器发出请求

但是如果我尝试从 subdomain.sitename.com 连接到 sitename.com:3334(只是一个不同的端口),它会给我一个 cors 错误:

跨域请求被阻止:同源策略不允许读取位于https://sitename.com:3334/graphql 的远程资源。 (原因:CORS 请求没有成功)

我已经在防火墙中打开了端口,并在服务器和客户端上设置了 ssl。

请帮忙!

客户端代码如下:

import { ApolloClient } from 'apollo-client'
import { withClientState } from 'apollo-link-state'
import { HttpLink } from 'apollo-link-http'
import { Agent } from 'https'
import fs from 'fs'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { setContext } from 'apollo-link-context'
import { onError } from 'apollo-link-error'
import { ApolloLink } from 'apollo-link'
import decode from 'jwt-decode'
import history from '../history'
import Cookies from 'universal-cookie'
import {
APP,
AUTH,
CLIENT_AUTH_REQUEST_TYPE,
CLIENT_AUTHENTICATION_METHOD,
JWT,
VERSION
} from '../environment'
import https from 'https'
import { defaults, resolvers } from '../api'
import { createUploadLink } from 'apollo-upload-client'

const { CONSTANTS: { UNAUTHORIZED, FORBIDDEN } = {} } = APP
const cookies = new Cookies()

const opts = {
credentials: 'same-origin',
headers: {
'frontend-version': VERSION,
[AUTH.STRATEGIES.CLIENT.AUTH_HEADER]: CLIENT_AUTH_REQUEST_TYPE
}
}

const useLocalStorage = CLIENT_AUTHENTICATION_METHOD.LOCAL_STORAGE
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = 0

// const apolloCache = new InMemoryCache();

const apolloCache = new InMemoryCache({
// dataIdFromObject: e => `${e.__typename}_${e.id}` || null // eslint- 
disable-line no-underscore-dangle
})

// const watchedMutationLink = new WatchedMutationLink(apolloCache, 
watchedMutations);
const stateLink = withClientState({
cache: apolloCache,
defaults,
resolvers
})

const uploadLink = createUploadLink({
// uri: 'http://localhost:3333/graphql',
uri: 'https://demo.MYSITE.in:3334/graphql',

fetchOptions: {
agent: new https.Agent()
}
})

const httpLink = new HttpLink({
uri: 'https://demo.MYSITE.in:3334/graphql',

...opts
})

const TOKEN_NAME = 'x-connector-token'

const authLink = new ApolloLink((operation, forward) => {
operation.setContext(({ headers = {} }) => {
const token = cookies.get('token')

if (token) {
  headers = { ...headers, 'x-connector-token': token }
}

return { headers }
})

return forward(operation)
})

const errorLink = onError(({ graphQLErrors, networkError }) => {
if (graphQLErrors && graphQLErrors.filter(e => e).length > 0) {
graphQLErrors.map(({ message = '', status = 200 }) => {
  if (UNAUTHORIZED === message || status === 401) {
    if (
      history &&
      history.location &&
      history.location.pathname !== '/login'
    ) {
      history.push('/login')
    }
  }
  if (FORBIDDEN === message || status === 403) {
    history.push(`/error-page/403`)
  }
  return null
})
}
if (networkError && networkError.statusCode === 401) {
// eslint-disable-next-line
history.push('/login')
}
if (networkError && networkError.statusCode === 403) {
// Do something
}
if (networkError && networkError.statusCode === 400) {
// Do something
}
if (networkError && networkError.statusCode >= 500) {
// eslint-disable-next-line

history.push(`/error-page/${networkError.statusCode}`)
}
})

let links = [errorLink, stateLink, httpLink]

links = [
errorLink,
stateLink,
// afterwareLink,
// authMiddlewareLink,
authLink,
// watchedMutationLink,
// httpLink,
uploadLink
]

const link = ApolloLink.from(links)


export default new ApolloClient({
link,
cache: apolloCache,
connectToDevTools: true,
// opts: {
//   agent
// },
fetchOptions: {
agent: new https.Agent()
// rejectUnauthorized: false
},
defaultOptions: {
query: {
  errorPolicy: 'all'
}
},

onError: ({ networkError, graphQLErrors }) => {}
})

服务器代码:

const app = express();

// tried this too
const corsOptions = {
origin: 'https://demo.MYSITE.in',
}
// also tried app.use(cors)
app.use(cors({
'allowedHeaders': ['Content-Type'],
'origin': '*',
'preflightContinue': true
}));

app.use(helmet());
// app.use(cors());

【问题讨论】:

  • 忘了说,客户端是安装在 nginx 上的 node/express 应用构建

标签: express server graphql


【解决方案1】:

浏览器不会向与网页本身的来源不同的来源(不同的端口构成不同的来源)的服务器发出请求,除非您在服务器上专门为该新来源启用该请求。这是一个花园品种 CORs 问题,其中有数百万关于如何处理的帖子和文章。由于您在问题中未显示任何代码,因此我们无法建议对您的代码进行特定的代码修复。

您的服务器需要支持您尝试执行的特定 CORS 请求。如果您使用的是 Express,那么 CORS module 会在正确实施的情况下为您完成很多工作。 CORS 可以保护您的网站,因此从浏览器运行的其他人网页中的 Javascript 不能任意使用您的 API,因此请谨慎对待您向 CORS 请求开放的内容。

而且,由于这对您来说似乎是一个新问题,我强烈建议您阅读并了解what CORs is and how it works。

另外,请注意,有“简单”CORS 请求和“预飞行请求”(非简单请求),需要做更多工作才能启用预飞行请求。浏览器根据请求的确切参数来决定给定的跨源请求是简单的还是需要预检,而您的服务器必须做更多的事情来启用预检请求。

【讨论】:

  • 客户端页面运行在nginx上,服务端在3333端口。服务端不服务页面,由nginx服务
  • @rainmaker - 我不确定那条评论是什么意思。关键是您试图向与页面来源不同的端口发出 Javascript 请求,从而使其跨源。因此,在浏览器允许之前,服务器需要对该特定类型的请求提供特定的跨源支持。您是否阅读过有关如何执行 COR 限制以及如何启用 COR 访问的任何内容?这都是成千上万的帖子和文章中涵盖的所有非常普通的东西。我今天在 stackoverflow 上就这个主题回答了多个问题。
  • 也许我不清楚。在端口 3333 上运行的服务器是 graphql 服务器。它不提供任何页面。客户端应用程序是独立的,并在安装在同一个盒子上的 nginx 上运行。我已经阅读了 cors 文档,但还没有找到解决方案。
  • 好吧,graphql 服务器必须启用 COR。
  • 我已经尝试过这个和许多其他选项......没有成功!常量应用程序 = 快递(); //CORS 中间件 const allowCrossDomain = function(req, res, next) { res.header('Access-Control-Allow-Origin', 'demo.MYSITE.in'); res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE'); res.header('Access-Control-Allow-Headers', 'Content-Type');下一个(); } app.use(头盔()); const corsOptions = { origin: 'demo.MYSITE.in' } //app.use(cors(corsOptions)); app.use(cors); app.use(morgan('dev'));
猜你喜欢
  • 2013-12-20
  • 2023-03-06
  • 1970-01-01
  • 2021-07-05
  • 1970-01-01
  • 1970-01-01
  • 2017-10-27
  • 1970-01-01
  • 2018-08-20
相关资源
最近更新 更多