URL Decode JavaScript — decodeURIComponent()

·Front-end & Node.js Developer·Beoordeeld doorMarcus Webb·Gepubliceerd

Gebruik de gratis URL Decode Online direct in je browser — geen installatie nodig.

URL Decode Online online uitproberen →

Percent-gecodeerde strings verschijnen constant in JavaScript-code — een zoekopdracht komt aan als q=standing+desk%26price%3A200, een OAuth- omleiding als next=https%3A%2F%2Fdashboard.internal%2F, een opslagpad als reports%2F2025%2Fq1.pdf. URL decoderen in JavaScript draait om het kiezen van de juiste van drie ingebouwde functies: decodeURIComponent(), decodeURI() en URLSearchParams — en de keuze daartussen is de hoofdoorzaak van de meeste stille datacorruptie die ik in productiecodebasen heb gezien, met name het +-als-spatie randgeval en dubbele decodering. Voor een snelle eenmalige decode zonder code te schrijven handelt de URL Decoder van ToolDeck het direct in de browser af. Deze JavaScript URL-decodering tutorial behandelt alle drie functies uitgebreid (ES2015+ / Node.js 10+): wanneer je elke functie gebruikt, hoe ze verschillen voor spaties en gereserveerde tekens, decodering vanuit bestanden en HTTP-verzoeken, veilige foutafhandeling en de vier fouten die de meeste subtiele productiebugs veroorzaken.

  • decodeURIComponent() decodeert alle percent-gecodeerde sequenties — het is de juiste keuze voor individuele queryparameterwaarden en padsegmenten
  • decodeURI() bewaart structurele URI-tekens zoals / ? & = # : — gebruik het alleen bij het decoderen van een volledige URL-string, nooit voor individuele waarden
  • URLSearchParams.get() geeft al gedecodeerde waarden terug — decodeURIComponent() er bovenop aanroepen veroorzaakt dubbele decodering
  • decodeURIComponent() decodeert + NIET als spatie — voor form-gecodeerde data (application/x-www-form-urlencoded) gebruik je URLSearchParams of vervang je + vóór het decoderen
  • Omsluit decodeURIComponent() altijd met try/catch wanneer de invoer afkomstig is van gebruikersdata — een kaal % of onvolledige sequentie gooit een URIError

Wat is URL-decodering?

Percent-codering (formeel gedefinieerd in RFC 3986) vervangt tekens die onveilig zijn of structurele betekenis hebben in een URL door een %-teken gevolgd door twee hexadecimale cijfers — de UTF-8-bytewaarde van het teken. URL-decodering keert deze transformatie om: elke %XX-sequentie wordt teruggeconverteerd naar zijn oorspronkelijke byte, en de resulterende bytereeks wordt geïnterpreteerd als UTF-8-tekst. Een spatie gedecodeerd uit %20, een schuine streep uit %2F, het niet-ASCII-teken ü uit %C3%BC (zijn twee-byte UTF-8-representatie).

De tekens die nooit gecodeerd worden — zogenaamde niet-gereserveerde tekens — zijn letters A–Z en a–z, cijfers 0–9 en - _ . ~. Al het andere heeft ofwel een structurele rol in de URL (zoals / voor het scheiden van padsegmenten of & voor het scheiden van queryparameters) of moet gecodeerd worden wanneer het als datawaarde wordt gebruikt. Het praktische resultaat: een zoekfilter zoals status=active&tier=premium gecodeerd als een enkele queryparameterwaarde ziet er bij aankomst totaal anders uit dan het origineel.

Before · text
After · text
// Percent-gecodeerd — zoals ontvangen in een HTTP-verzoek of webhook-payload
"q=price%3A%5B200+TO+800%5D%20AND%20brand%3ANorthwood%20%26%20status%3Ain-stock"
// Na URL-decodering — het originele Elasticsearch-queryfilter
"q=price:[200 TO 800] AND brand:Northwood & status:in-stock"

decodeURIComponent() — De standaardfunctie voor het decoderen van waarden

decodeURIComponent() is het werkpaard van URL-decodering in JavaScript. Het decodeert elke %XX-sequentie in de invoerstring — inclusief tekens die een structurele betekenis hebben in een URL, zoals %2F (schuine streep), %3F (vraagteken), %26 (ampersand) en %3D (gelijkteken). Dit maakt het de juiste keuze voor het decoderen van individuele queryparameterwaarden en padsegmenten, maar de verkeerde keuze voor het decoderen van een volledige URL — waar die structurele tekens gecodeerd moeten blijven. Het is een globale functie: er is geen import nodig in een JavaScript-omgeving.

Minimaal werkend voorbeeld

JavaScript (browser / Node.js)
// Individuele queryparameterwaarden decoderen — het gebruikelijke geval

const city     = decodeURIComponent('S%C3%A3o%20Paulo')          // 'São Paulo'
const district = decodeURIComponent('It%C3%A1im%20Bibi')         // 'Itáim Bibi'
const category = decodeURIComponent('office%20furniture')         // 'office furniture'
const filter   = decodeURIComponent('price%3A%5B200+TO+800%5D')  // 'price:[200+TO+800]'
// Opmerking: + wordt NIET gedecodeerd als spatie — zie de +-sectie in de vergelijkingstabel

console.log(city)      // São Paulo
console.log(district)  // Itáim Bibi
console.log(category)  // office furniture
console.log(filter)    // price:[200+TO+800]

Een omleidings-URL geëxtraheerd uit een queryparameter decoderen

JavaScript
// De omleidings-URL was percent-gecodeerd toen het als parameterwaarde werd ingebed
// ontvangend einde: extraheer het, gebruik het dan — geen handmatige decodering nodig met URLSearchParams

const incomingUrl = 'https://auth.company.com/callback' +
  '?next=https%3A%2F%2Fdashboard.internal%2Freports%3Fview%3Dweekly%26team%3Dplatform' +
  '&session_id=sid_7x9p2k'

const url       = new URL(incomingUrl)
const rawNext   = url.searchParams.get('next')       // Automatisch gedecodeerd door URLSearchParams
const sessionId = url.searchParams.get('session_id') // 'sid_7x9p2k'

// rawNext is al gedecodeerd: 'https://dashboard.internal/reports?view=weekly&team=platform'
// Roep decodeURIComponent(rawNext) NIET opnieuw aan — dat zou dubbele decodering zijn

const nextUrl = new URL(rawNext!)
console.log(nextUrl.hostname)                    // dashboard.internal
console.log(nextUrl.searchParams.get('view'))    // weekly
console.log(nextUrl.searchParams.get('team'))    // platform

Niet-ASCII- en Unicode-padsegmenten decoderen

JavaScript
// REST-API met geïnternationaliseerde padsegmenten
// Elke UTF-8-byte van het originele teken werd apart percent-gecodeerd

const encodedSegments = [
  '%E6%9D%B1%E4%BA%AC',   // 東京  (Tokio)   — 3 bytes per teken
  'M%C3%BCnchen',         // München          — ü gecodeerd als 2 bytes
  'caf%C3%A9',            // café             — é als samengestelde NFC
  'S%C3%A3o%20Paulo',     // São Paulo
]

encodedSegments.forEach(seg => {
  console.log(decodeURIComponent(seg))
})
// 東京
// München
// café
// São Paulo

// Een bestandssleutel extraheren uit een storage-API-URL
// De objectsleutel bevatte een / dus was gecodeerd als %2F binnen het padsegment
const storageUrl = 'https://storage.api.example.com/v1/objects/reports%2F2025%2Fq1-financials.pdf'
const rawKey     = new URL(storageUrl).pathname.replace('/v1/objects/', '')
// .pathname decodeert de URL-niveau-codering maar %2F (als %252F op URL-niveau) blijft
// Gebruik decodeURIComponent voor de laatste stap:
const fileKey = decodeURIComponent(rawKey)  // 'reports/2025/q1-financials.pdf'
console.log(fileKey)
Opmerking:decodeURIComponent() gooit een URIError wanneer de invoer een % bevat dat niet wordt gevolgd door twee geldige hexadecimale cijfers — bijvoorbeeld een kaal % aan het einde van een string of een sequentie zoals %GH. Omsluit het altijd met try/catch bij het decoderen van door de gebruiker opgegeven invoer. De veilige decoderingspatronen worden behandeld in de sectie Foutafhandeling hieronder.

JavaScript URL-decoderingsfuncties — Tekenreferentie

De drie ingebouwde decoderingsfuncties verschillen in precies welke gecodeerde sequenties ze decoderen. De tabel toont het gedrag voor de tekens die het meest van belang zijn in de praktijk:

GecodeerdTekendecodeURIComponent()decodeURI()URLSearchParams
%20spatiespatie ✅spatie ✅spatie ✅
+plus (form)+ (behouden)+ (behouden)spatie ✅
%2B+ literal+ ✅+ ✅+ ✅
%26&& ✅& (behouden) ❌& ✅
%3D== ✅= (behouden) ❌= ✅
%3F?? ✅? (behouden) ❌? ✅
%23## ✅# (behouden) ❌# ✅
%2F// ✅/ (behouden) ❌/ ✅
%3A:: ✅: (behouden) ❌: ✅
%40@@ ✅@ (behouden) ❌@ ✅
%25%% ✅% ✅% ✅
%C3%BCüü ✅ü ✅ü ✅

De twee kritieke rijen zijn + en de structurele tekens (%26, %3D, %3F). URLSearchParams decodeert + als een spatie omdat het de application/x-www-form-urlencoded-specificatie volgt — correct voor HTML-formulierverzendingen, maar anders dan wat decodeURIComponent() doet met hetzelfde teken. En decodeURI() slaat stil %26, %3D en %3F over — wat er correct uitziet totdat een waarde daadwerkelijk een gecodeerd ampersand of gelijkteken bevat.

decodeURI() — Een volledige URL decoderen zonder de structuur te beschadigen

decodeURI() is het tegenhanger van encodeURI(). Het decodeert een volledige URL-string terwijl tekens met structurele betekenis in een URI worden bewaard: ; , / ? : @ & = + $ #. Deze worden gelaten als hun percent-gecodeerde vorm (of als letterlijke tekens als ze ongecodeerd in de invoer voorkwamen). Dit maakt decodeURI()veilig voor het opschonen van volledige URL's die niet-ASCII-tekens in het pad of de hostnaam kunnen bevatten, zonder per ongeluk de querystring-structuur te beschadigen.

Een URL met niet-ASCII-padsegmenten opschonen

JavaScript
// Een CDN-URL met geïnternationaliseerde padsegmenten en een gestructureerde querystring
// decodeURI() decodeert niet-ASCII-pad maar bewaart ? & = intact

const encodedUrl =
  'https://cdn.example.com/assets/%E6%9D%B1%E4%BA%AC%2F2025%2Fq1-report.pdf' +
  '?token=eyJ0eXAiOiJKV1QiLCJhbGci&expires=1735689600'

const readable = decodeURI(encodedUrl)
console.log(readable)
// https://cdn.example.com/assets/東京/2025/q1-report.pdf?token=eyJ0eXAiOiJKV1QiLCJhbGci&expires=1735689600
// ↑ Niet-ASCII gedecodeerd; ? & = bewaard — URL blijft structureel geldig

// decodeURIComponent zou de URL vernietigen — : / ? & = worden allemaal tegelijk gedecodeerd
const broken = decodeURIComponent(encodedUrl)
// Ziet er hier hetzelfde uit, maar een URL als 'https%3A%2F%2F...' zou worden vernietigd
Opmerking:Geef de voorkeur aan de URL-constructor boven decodeURI() wanneer je ook toegang nodig hebt tot individuele URL-componenten. new URL(str) normaliseert de invoer, valideert de structuur en maakt .pathname, .searchParams en .hostname beschikbaar als al gedecodeerde eigenschappen. Reserveer decodeURI() voor gevallen waarbij je alleen een tekenreeksresultaat nodig hebt en de URL-constructor niet kunt gebruiken (bijvoorbeeld in zeer oude Node.js 6-omgevingen zonder de globale URL-klasse).

URLSearchParams — Automatische decodering voor querystrings

URLSearchParams is de idiomatische manier om querystrings te parsen in modern JavaScript. Elke waarde die wordt geretourneerd door .get(), .getAll() of iteratie is automatisch gedecodeerd — inclusief + als spatie voor form-gecodeerde data. Het is globaal beschikbaar in alle moderne browsers en Node.js 10+, vereist geen import en behandelt randgevallen die handmatig string-splitten fout doet.

Een inkomende querystring parsen

JavaScript (browser / Node.js 10+)
// Een webhook-callback of OAuth-omleiding querystring parsen
const rawSearch =
  '?event_id=evt_9c2f4a1b' +
  '&product_name=Standing+Desk+Pro' +
  '&filter=price%3A%5B200+TO+800%5D' +
  '&tag=ergonomic&tag=adjustable' +
  '&redirect=https%3A%2F%2Fdashboard.internal%2Forders%3Fview%3Dpending'

const params = new URLSearchParams(rawSearch)

console.log(params.get('event_id'))      // 'evt_9c2f4a1b'
console.log(params.get('product_name'))  // 'Standing Desk Pro'       ← + gedecodeerd als spatie
console.log(params.get('filter'))        // 'price:[200+TO+800]'      ← %3A en %5B gedecodeerd
console.log(params.getAll('tag'))        // ['ergonomic', 'adjustable']
console.log(params.get('redirect'))      // 'https://dashboard.internal/orders?view=pending'

// Alle parameters itereren
for (const [key, value] of params) {
  console.log(`${key}: ${value}`)
}
// event_id: evt_9c2f4a1b
// product_name: Standing Desk Pro
// filter: price:[200+TO+800]
// tag: ergonomic
// tag: adjustable
// redirect: https://dashboard.internal/orders?view=pending

Queryparameters parsen uit de huidige browser-URL

JavaScript (browser)
// Huidige URL: https://app.example.com/search
//   ?q=standing+desk
//   &category=office+furniture
//   &sort=price_asc
//   &page=2

interface SearchFilters {
  query:    string | null
  category: string | null
  sort:     string
  page:     number
}

function getSearchFilters(): SearchFilters {
  const params = new URLSearchParams(window.location.search)
  return {
    query:    params.get('q'),                       // 'standing desk'
    category: params.get('category'),                // 'office furniture'
    sort:     params.get('sort') ?? 'relevance',
    page:     Number(params.get('page') ?? '1'),
  }
}

const filters = getSearchFilters()
console.log(filters.query)     // standing desk   (+ automatisch gedecodeerd)
console.log(filters.category)  // office furniture

URL-gecodeerde data decoderen uit bestanden en API-antwoorden

Twee scenario's komen constant terug in echte projecten: het verwerken van een bestand op schijf dat percent-gecodeerde data bevat (toegangslogs, data-exports, webhook-opnamebestanden), en het parsen van de URL van een inkomend HTTP-verzoek in een Node.js-server. Beide volgen hetzelfde principe — gebruik de URL-constructor of URLSearchParams in plaats van handmatig string-splitten — maar de details verschillen.

URL-gecodeerde records uit een bestand lezen en decoderen

JavaScript (Node.js 10+)
import { createReadStream } from 'fs'
import { createInterface } from 'readline'

// Bestand: orders-export.txt — één URL-gecodeerd record per regel
// customer_name=Jan+de+Vries&order_id=ord_9c2f4a&product=Standing+Desk+Pro&total=149.99%20EUR
// customer_name=Emma+Visser&order_id=ord_7b3a1c&product=Ergonomic+Chair&total=89.00%20EUR
// customer_name=Jan+de+Vries&order_id=ord_2e8d5f&product=Monitor+Arm&total=59.00%20EUR

interface Order {
  customerName: string | null
  orderId:      string | null
  product:      string | null
  total:        string | null
}

async function parseOrdersFile(filePath: string): Promise<Order[]> {
  const fileStream = createReadStream(filePath, { encoding: 'utf-8' })
  const rl         = createInterface({ input: fileStream, crlfDelay: Infinity })
  const orders: Order[] = []

  for await (const line of rl) {
    if (!line.trim()) continue

    // URLSearchParams decodeert + als spatie en %XX-sequenties automatisch
    const params = new URLSearchParams(line)

    orders.push({
      customerName: params.get('customer_name'),  // 'Jan de Vries'
      orderId:      params.get('order_id'),        // 'ord_9c2f4a'
      product:      params.get('product'),         // 'Standing Desk Pro'
      total:        params.get('total'),           // '149.99 EUR'
    })
  }

  return orders
}

const orders = await parseOrdersFile('./orders-export.txt')
console.log(orders[0])
// { customerName: 'Jan de Vries', orderId: 'ord_9c2f4a', product: 'Standing Desk Pro', total: '149.99 EUR' }

Een Nginx-toegangslog parsen om zoekopdrachten te decoderen

JavaScript (Node.js)
import { createReadStream } from 'fs'
import { createInterface } from 'readline'

// Nginx-toegangslog-regels zien er zo uit:
// 192.168.1.42 - - [11/Mar/2026:10:23:01 +0000] "GET /api/search?q=standing%20desk%26brand%3ANorthwood&sort=price_asc HTTP/1.1" 200 1842

async function extractSearchQueries(logFile: string): Promise<string[]> {
  const rl     = createInterface({ input: createReadStream(logFile), crlfDelay: Infinity })
  const queries: string[] = []

  for await (const line of rl) {
    // Het verzoekpad uit de logregel extraheren
    const match = line.match(/"GET ([^ ]+) HTTP/)
    if (!match) continue

    try {
      const requestUrl = new URL(match[1], 'http://localhost')
      const query      = requestUrl.searchParams.get('q')
      if (query) queries.push(query)  // URLSearchParams decodeert automatisch
    } catch {
      // Foutieve regels overslaan — toegangslogs kunnen afgeknipte vermeldingen bevatten
    }
  }

  return queries
}

const queries = await extractSearchQueries('/var/log/nginx/access.log')
console.log(queries)
// ['standing desk&brand:Northwood', 'ergonomic chair', 'monitor arm 27 inch']

Queryparameters parsen in een Node.js HTTP-server

JavaScript (Node.js 10+)
import http from 'http'

// Inkomende URL: /api/products?q=standing+desk&warehouse=eu%2Dwest%2D1&minStock=10&cursor=eyJpZCI6MTIzfQ%3D%3D

const server = http.createServer((req, res) => {
  // Een volledige URL construeren — het tweede argument is de basis vereist door de URL-constructor
  const requestUrl = new URL(req.url!, 'http://localhost')

  const searchQuery = requestUrl.searchParams.get('q')            // 'standing desk'
  const warehouseId = requestUrl.searchParams.get('warehouse')    // 'eu-west-1'
  const minStock    = Number(requestUrl.searchParams.get('minStock') ?? '0')
  const cursor      = requestUrl.searchParams.get('cursor')       // 'eyJpZCI6MTIzfQ=='

  if (!warehouseId) {
    res.writeHead(400, { 'Content-Type': 'application/json' })
    res.end(JSON.stringify({ error: 'warehouse parameter is required' }))
    return
  }

  const cursorData = cursor ? JSON.parse(Buffer.from(cursor, 'base64').toString()) : null

  res.writeHead(200, { 'Content-Type': 'application/json' })
  res.end(JSON.stringify({ searchQuery, warehouseId, minStock, cursorData }))
})

server.listen(3000)

Wanneer je een gecodeerde URL wilt inspecteren tijdens ontwikkeling — om te begrijpen wat een webhook stuurt voordat je de parsing-code schrijft — plak hem direct in de URL Decoder van ToolDeck om de gedecodeerde vorm direct te zien zonder een script uit te voeren.

URL-decodering via de opdrachtregel

Voor shellscripts, CI-pipelines of snelle eenmalige inspectie van gecodeerde strings werken verschillende benaderingen zonder een volledig script te schrijven. Node.js-oneliner zijn platformonafhankelijk; op macOS en Linux is ook altijd python3 beschikbaar.

bash
# ── Node.js one-liners ──────────────────────────────────────────────────

# Een enkele percent-gecodeerde waarde decoderen
node -e "console.log(decodeURIComponent(process.argv[1]))" "S%C3%A3o%20Paulo%20%26%20Rio"
# São Paulo & Rio

# Een querystring parsen en elk sleutel=waarde-paar afdrukken (gedecodeerd)
node -e "
  const params = new URLSearchParams(process.argv[1])
  for (const [k, v] of params) console.log(`${k} = ${v}`)
" "q=standing+desk&warehouse=eu%2Dwest%2D1&minStock=10"
# q = standing desk
# warehouse = eu-west-1
# minStock = 10

# Een URL-gecodeerde JSON-body decoderen en netjes afdrukken (gebruikelijk bij webhook-debugging)
node -e "
  const raw = decodeURIComponent(process.argv[1])
  console.log(JSON.stringify(JSON.parse(raw), null, 2))
" '%7B%22event%22%3A%22purchase%22%2C%22amount%22%3A149.99%2C%22currency%22%3A%22EUR%22%7D'
# {
#   "event": "purchase",
#   "amount": 149.99,
#   "currency": "EUR"
# }

# ── Python one-liner (beschikbaar op de meeste macOS/Linux-systemen) ─────
# unquote_plus decodeert ook + als spatie — correct voor form-gecodeerde data
python3 -c "
from urllib.parse import unquote_plus
import sys
print(unquote_plus(sys.argv[1]))
" "Standing+Desk+%26+Ergonomic+Chair"
# Standing Desk & Ergonomic Chair

# ── curl — een omleidings-URL uit een antwoordheader vastleggen en decoderen ──────────
curl -sI "https://api.example.com/short/abc123" | grep -i location |   node -e "
    const line = require('fs').readFileSync('/dev/stdin', 'utf8')
    const url  = line.replace(/^location:s*/i, '').trim()
    console.log(decodeURIComponent(url))
  "

Tolerante decodering met decode-uri-component

De ingebouwde decodeURIComponent() gooit een URIError bij elke foutieve sequentie — inclusief een afsluitende %zonder twee volgende hexcijfers. In productiecode die door de gebruiker opgegeven of derdepartij-URL's verwerkt — zoekquery-logs, doorklikURL's uit e-mailcampagnes, gescrapte webdata — zijn foutieve sequenties vaak genoeg om crashes te veroorzaken. Het decode-uri-component-pakket (~30 miljoen wekelijkse npm-downloads) behandelt foutieve sequenties tolerant door de oorspronkelijke sequentie ongewijzigd te retourneren in plaats van te gooien.

bash
npm install decode-uri-component
# of
pnpm add decode-uri-component
JavaScript (Node.js)
import decodeUriComponent from 'decode-uri-component'

// Native functie gooit bij foutieve invoer — kan een request-handler laten crashen
try {
  decodeURIComponent('product%name%')   // ❌ URIError: URI malformed
} catch (e) {
  console.error('Native gooide:', (e as Error).message)
}

// decode-uri-component geeft de ruwe sequentie terug in plaats van te gooien
console.log(decodeUriComponent('product%name%'))
// product%name%   ← foutieve sequenties ongewijzigd gelaten, geen gooi

// Geldige sequenties worden correct gedecodeerd
console.log(decodeUriComponent('S%C3%A3o%20Paulo%20%26%20Rio'))
// São Paulo & Rio

// Gemengd: geldige sequenties gedecodeerd, ongeldige bewaard
console.log(decodeUriComponent('Amsterdam%20Office%20%ZZ%20HQ'))
// Amsterdam Office %ZZ HQ   ← %ZZ is geen geldig hex — ongewijzigd gelaten

// Praktisch gebruik in een logverwerkingspijplijn
const rawSearchQueries = [
  'standing%20desk%20ergonomic',
  'price%3A%5B200+TO+800%5D',
  '50%25+off',       // ← zou gooien met decodeURIComponent (kaal %)
  'wireless%20keyboard%20%26%20mouse',
]

const decoded = rawSearchQueries.map(q => decodeUriComponent(q))
console.log(decoded)
// ['standing desk ergonomic', 'price:[200+TO+800]', '50%25+off', 'wireless keyboard & mouse']

Gebruik decodeURIComponent() met een try/catch voor applicatiecode waarbij je direct wilt weten wanneer onverwachte invoer aankomt. Grijp naar decode-uri-component in datapijplijnen, logprocessors en webhook-handlers waarbij je door wilt gaan met verwerken ook wanneer sommige invoer ongeldige codering bevat.

Foutief percent-gecodeerde strings afhandelen

Een kaal %, een onvolledige sequentie zoals %A, of een ongeldig paar zoals %GH zorgen er allemaal voor dat decodeURIComponent() URIError: URI malformedgooit. Elke door de gebruiker beheerde invoer — zoekopdrachten, URL-fragmenten, formuliervelden die URL's bevatten, parameters van e-mailcampagnelinks — kan deze sequenties bevatten. Een veilige wrapper is essentieel voor externe code.

Veilige decoderings-wrappers voor veelvoorkomende scenario's

JavaScript
// ── 1. Basis veilige decodering — geeft de originele string terug bij fout ─────────────
function safeDecode(encoded: string): string {
  try {
    return decodeURIComponent(encoded)
  } catch {
    return encoded  // ruwe invoer teruggeven als decodering mislukt — nooit crashen
  }
}

// ── 2. Veilige decodering + behandel + als spatie (voor form-gecodeerde waarden) ─────────
function safeFormDecode(formEncoded: string): string {
  try {
    return decodeURIComponent(formEncoded.replace(/+/g, ' '))
  } catch {
    return formEncoded.replace(/+/g, ' ')  // vervang in ieder geval + zelfs als de rest mislukt
  }
}

// ── 3. Veilige volledige querystring-parser → gewoon object ──────────────────────────────
function parseQueryString(queryString: string): Record<string, string> {
  const result: Record<string, string> = {}
  try {
    const params = new URLSearchParams(queryString)
    for (const [key, value] of params) {
      result[key] = value  // URLSearchParams behandelt alle decodering intern
    }
  } catch {
    // Stilletjes leeg teruggeven bij volledig foutieve invoer
  }
  return result
}

// Gebruik
console.log(safeDecode('S%C3%A3o%20Paulo'))         // São Paulo
console.log(safeDecode('search%20for%2050%25+off'))  // search for 50% off (kaal %)
                                                     // → eigenlijk prima; % hier is %25
console.log(safeDecode('malformed%string%'))         // malformed%string%  (geen gooi)

console.log(safeFormDecode('standing+desk+pro'))     // standing desk pro

console.log(parseQueryString('q=hello+world&tag=node%20js&page=2'))
// { q: 'hello world', tag: 'node js', page: '2' }

Veelgemaakte fouten

Ik heb deze vier patronen stille datacorruptie of onverwachte crashes in productie zien veroorzaken — gewoonlijk alleen wanneer een waarde toevallig een speciaal teken bevat, wat betekent dat ze door unit-tests glippen en alleen aan de oppervlakte komen met echte gebruikersdata.

Fout 1 — Een URLSearchParams-waarde dubbel decoderen

Probleem: URLSearchParams.get() geeft een al gedecodeerde string terug. Het aanroepen van decodeURIComponent() er bovenop decodeert de waarde dubbel — waardoor resterende %-tekens in de gedecodeerde uitvoer worden omgezet naar %25, wat de data beschadigt. Oplossing: gebruik de waarde van URLSearchParams.get() direct — er is geen extra decodering nodig.

Before · JavaScript
After · JavaScript
// ❌ URLSearchParams heeft al gedecodeerd — opnieuw decoderen beschadigt waarden met %
const qs        = new URLSearchParams('rate=50%25&redirect=https%3A%2F%2Fdashboard.internal%2F')
const rawRate   = qs.get('rate')       // '50%'   ← al gedecodeerd
const wrongRate = decodeURIComponent(rawRate)
// '50%25'  ← % werd op de tweede doorgang naar %25 gedecodeerd — nu weer fout
// ✅ Gebruik URLSearchParams.get() direct — decodering is automatisch
const qs       = new URLSearchParams('rate=50%25&redirect=https%3A%2F%2Fdashboard.internal%2F')
const rate     = qs.get('rate')        // '50%'   ← correct, geen extra stap nodig
const redirect = qs.get('redirect')    // 'https://dashboard.internal/'
const parsed   = new URL(redirect!)    // Veilig te construeren — al gedecodeerd
console.log(parsed.hostname)           // dashboard.internal

Fout 2 — + niet decoderen als spatie voor form-gecodeerde data

Probleem: Formulierverzendingen en sommige OAuth-bibliotheken coderen spaties als + (application/x-www-form-urlencoded). Het aanroepen van decodeURIComponent() op deze data laat + als een letterlijk plusteken. Oplossing: gebruik URLSearchParams om form-gecodeerde data te parsen, of vervang + door een spatie voordat je decodeURIComponent() aanroept.

Before · JavaScript
After · JavaScript
// ❌ decodeURIComponent behandelt + als een letterlijk plusteken, niet als spatie
// OAuth-tokeneindpunt stuurt: grant_type=authorization_code&code=SplxlOBeZQQYb...
//   &redirect_uri=https%3A%2F%2Fapp.example.com%2Fcallback
// Sommige legacy-OAuth-implementaties gebruiken ook + voor spaties in codes
const formBody   = 'customer_name=Jan+de+Vries&product=Standing+Desk+Pro&qty=2'
const [, rawVal] = formBody.split('&')[0].split('=')
const name       = decodeURIComponent(rawVal)
console.log(name)  // 'Jan+de+Vries'  ← + niet omgezet naar spatie
// ✅ Gebruik URLSearchParams — volgt de application/x-www-form-urlencoded-spec
const formBody   = 'customer_name=Jan+de+Vries&product=Standing+Desk+Pro&qty=2'
const params     = new URLSearchParams(formBody)
console.log(params.get('customer_name'))  // 'Jan de Vries'   ← + correct gedecodeerd als spatie
console.log(params.get('product'))        // 'Standing Desk Pro'

Fout 3 — decodeURI() gebruiken voor individuele queryparameterwaarden

Probleem: decodeURI() decodeert %26 (&), %3D (=) of %3F (?) niet — tekens die gewoonlijk worden gecodeerd in parameterwaarden. Het gebruiken om een enkele waarde te decoderen laat die sequenties intact en produceert stilletjes onjuiste uitvoer. Oplossing: gebruik decodeURIComponent() voor individuele waarden; reserveer decodeURI() voor volledige URL-strings.

Before · JavaScript
After · JavaScript
// ❌ decodeURI decodeert & en = niet — de waarde blijft beschadigd
const encodedFilter = 'status%3Dactive%26tier%3Dpremium%26region%3Deu-west'
const filter        = decodeURI(encodedFilter)
console.log(filter)
// 'status%3Dactive%26tier%3Dpremium%26region%3Deu-west'  ← %3D en %26 niet gedecodeerd
// ✅ decodeURIComponent decodeert alle sequenties inclusief & en =
const encodedFilter = 'status%3Dactive%26tier%3Dpremium%26region%3Deu-west'
const filter        = decodeURIComponent(encodedFilter)
console.log(filter)
// 'status=active&tier=premium&region=eu-west'  ← correct gedecodeerd

Fout 4 — decodeURIComponent niet in try/catch wikkelen voor gebruikersinvoer

Probleem: Een kaal %dat niet wordt gevolgd door twee hexcijfers — gebruikelijk in door gebruikers getypte zoekopdrachten (“50% korting”, “100% katoen”) — zorgt ervoor dat decodeURIComponent() URIError: URI malformed gooit, waardoor de request-handler crasht als het onbehandeld blijft. Oplossing: omsluit altijd in try/catch wanneer invoer afkomstig is van gebruikersdata, URL-fragmenten of externe systemen.

Before · JavaScript
After · JavaScript
// ❌ Gebruiker typte '100% katoen' in een zoekvak — kaal % brengt server tot crash
// GET /api/search?q=100%25+katoen  ← Dit specifieke geval is prima (%25 = %)
// GET /api/search?q=100%+katoen    ← Dit crasht (% niet gevolgd door 2 hexcijfers)
app.get('/api/search', (req, res) => {
  const query = decodeURIComponent(req.query.q as string)
  // ↑ gooit URIError: URI malformed voor '100% katoen'  → onbehandelde 500-fout
})
// ✅ Wikkel in try/catch — val terug op ruwe invoer als decodering mislukt
app.get('/api/search', (req, res) => {
  let query: string
  try {
    query = decodeURIComponent(req.query.q as string)
  } catch {
    query = req.query.q as string  // gebruik de ruwe waarde in plaats van te crashen
  }
  // ga veilig door met verwerken — query is ofwel gedecodeerd of ruw
})

decodeURIComponent vs decodeURI vs URLSearchParams — Snelle vergelijking

MethodeDecodeert %XXDecodeert + als spatieGooit bij foutieve invoerDecodeert & = ? #GebruiksscenarioInstallatie vereist
decodeURIComponent()✅ alle❌ nee✅ URIError✅ jaIndividuele waarden en padsegmentenNee
decodeURI()✅ meeste❌ nee✅ URIError❌ neeVolledige URL-stringsNee
URLSearchParams✅ alle✅ ja❌ stil✅ jaQuerystring-parsing met automatische decoderingNee
URL-constructor✅ alle✅ ja✅ TypeError✅ jaVolledige URL-parsing en normalisatieNee
decode-uri-component✅ alle❌ nee❌ stil✅ jaBatch-decodering met tolerantie voor foutieve invoernpm install
querystring.unescape()✅ alle❌ nee❌ stil✅ jaLegacy Node.js (verouderd sinds v16)Nee (ingebouwd)

In de overgrote meerderheid van gevallen reduceert de keuze tot drie scenario's. Gebruik URLSearchParams om querystrings te parsen — het handelt decodering, de +-als-spatie-regel en herhaalde sleutels automatisch af. Gebruik decodeURIComponent() (omsloten in try/catch) voor een enkele waarde of padsegment, met name wanneer je %2F-gecodeerde schuine strepen binnen een segment verwacht. Gebruik decodeURI() alleen wanneer je een volledige URL-string hebt met niet-ASCII-tekens in het pad en de structurele tekens (/ ? & =) gecodeerd moeten blijven in de uitvoer.

Veelgestelde vragen

Wat is het verschil tussen decodeURIComponent() en decodeURI() in JavaScript?
decodeURIComponent() decodeert elke percent-gecodeerde sequentie in de string, inclusief tekens die structurele betekenis hebben in een URL — & (%26), = (%3D), ? (%3F), # (%23), / (%2F) en : (%3A). Het is ontworpen voor het decoderen van individuele queryparameterwaarden of padsegmenten. decodeURI() bewaart die structurele tekens — het decodeert %26, %3D, %3F, %23, %2F of %3A niet — omdat het is ontworpen om een volledige URL op te schonen zonder de querystring-structuur te beschadigen. decodeURI() gebruiken op een enkele parameterwaarde die een gecodeerd & of = bevat, laat die sequenties stilletjes ongedecodeerd en produceert onjuiste uitvoer.
Waarom gooit decodeURIComponent() een URIError voor sommige strings?
decodeURIComponent() gooit URIError: URI malformed wanneer de invoer een % bevat dat niet wordt gevolgd door exact twee geldige hexadecimale cijfers. Veelvoorkomende triggers: een kaal % aan het einde van een string ("50% korting" getypt door een gebruiker), een onvolledige sequentie ("%A"), of een niet-hex-paar ("%GH"). Dit gebeurt het vaakst bij door gebruikers getypte zoekopdrachten of waarden geplakt uit tekst die nooit bedoeld was als URL-gecodeerd. De oplossing is decodeURIComponent() in een try/catch-blok te wikkelen en bij een fout de ruwe string terug te geven. Het decode-uri-component npm-pakket biedt dezelfde oplossing zonder een try/catch-wrapper te vereisen.
Decodeert URLSearchParams percent-gecodeerde waarden automatisch?
Ja. Elke waarde die wordt geretourneerd door URLSearchParams.get() en URLSearchParams.getAll() is volledig gedecodeerd — je moet nooit decodeURIComponent() aanroepen op hun uitvoer. URLSearchParams volgt ook de application/x-www-form-urlencoded-specificatie, die + decodeert als een spatie, wat het correct maakt voor HTML-formulierverzendingen en OAuth-tokenantwoorden. Het enige geval waarbij URLSearchParams niet kan helpen is het decoderen van een zelfstandige gecodeerde waarde die geen deel uitmaakt van een querystring — gebruik daarvoor decodeURIComponent() met een try/catch.
Hoe decodeer ik het +-teken als spatie in JavaScript?
decodeURIComponent() behandelt + als een letterlijk plusteken — het converteert + niet naar een spatie. Dit is opzettelijk: + als spatie is een application/x-www-form-urlencoded-conventie, los van de percent-coderingsstandaard. Om + als spatie te decoderen, gebruik je URLSearchParams (dat de form-gecodeerde spec volgt), of vervang je + voor het aanroepen van decodeURIComponent(): decodeURIComponent(str.replace(/\+/g, ' ')). Merk op dat het vervangen van + door %20 voor het decoderen ook werkt maar iets uitgebreider is. Geef altijd de voorkeur aan URLSearchParams voor het parsen van volledige querystrings — het behandelt zowel %20 als + correct.
Hoe decodeer ik een string via URL in Node.js?
Gebruik dezelfde globale functies die beschikbaar zijn in alle browsers — in Node.js 10+ is geen import nodig. decodeURIComponent() voor individuele waarden, decodeURI() voor volledige URL-strings, URLSearchParams voor querystrings. Voor inkomende HTTP-verzoek-URL&apos;s, gebruik new URL(req.url, 'http://localhost') — de URL-constructor normaliseert de URL en maakt .searchParams (automatisch gedecodeerd) en .pathname (gedecodeerd op URL-niveau) beschikbaar. De oudere querystring.unescape()-functie bestaat nog maar is verouderd sinds Node.js 16 — gebruik in plaats daarvan decodeURIComponent().
Hoe parse ik een URL-querystring naar een object in JavaScript?
Gebruik URLSearchParams met Object.fromEntries(): const params = Object.fromEntries(new URLSearchParams(queryString)). Dit geeft een gewoon object met alle parametersleutels en gedecodeerde waarden. Merk op dat Object.fromEntries() bij dubbele sleutels alleen de laatste waarde behoudt — voor herhaalde sleutels zoals tag=one&tag=two, gebruik in plaats daarvan URLSearchParams.getAll('tag'). Voor de browser parseert new URLSearchParams(window.location.search) de querystring van de huidige pagina automatisch. Voor Node.js, parseer van new URL(req.url, base).searchParams.

Gerelateerde tools

Voor een één-klik-decodering zonder code te schrijven, plak je percent-gecodeerde string direct in de URL Decoder van ToolDeck — het decodeert direct in de browser, met het resultaat klaar om te kopiëren naar je code of terminal.

AC
Alex ChenFront-end & Node.js Developer

Alex is a front-end and Node.js developer with extensive experience building web applications and developer tooling. He is passionate about web standards, browser APIs, and the JavaScript ecosystem. In his spare time he contributes to open-source projects and writes about modern JavaScript patterns, performance optimisation, and everything related to the web platform.

MW
Marcus WebbTechnisch beoordelaar

Marcus specialises in JavaScript performance, build tooling, and the inner workings of the V8 engine. He has spent years profiling and optimising React applications, working on bundler configurations, and squeezing every millisecond out of critical rendering paths. He writes about Core Web Vitals, JavaScript memory management, and the tools developers reach for when performance really matters.